merge unbound 1.15.0
authorsthen <sthen@openbsd.org>
Wed, 23 Feb 2022 12:04:05 +0000 (12:04 +0000)
committersthen <sthen@openbsd.org>
Wed, 23 Feb 2022 12:04:05 +0000 (12:04 +0000)
95 files changed:
usr.sbin/unbound/Makefile.in
usr.sbin/unbound/README.md
usr.sbin/unbound/acx_nlnetlabs.m4
usr.sbin/unbound/cachedb/cachedb.c
usr.sbin/unbound/config.guess
usr.sbin/unbound/config.h.in
usr.sbin/unbound/config.sub
usr.sbin/unbound/configure
usr.sbin/unbound/configure.ac
usr.sbin/unbound/daemon/daemon.c
usr.sbin/unbound/daemon/remote.c
usr.sbin/unbound/daemon/stats.c
usr.sbin/unbound/daemon/unbound.c
usr.sbin/unbound/daemon/worker.c
usr.sbin/unbound/dns64/dns64.c
usr.sbin/unbound/dnscrypt/dnscrypt.c
usr.sbin/unbound/dnscrypt/dnscrypt.h
usr.sbin/unbound/doc/Changelog
usr.sbin/unbound/doc/README
usr.sbin/unbound/doc/example.conf.in
usr.sbin/unbound/doc/libunbound.3.in
usr.sbin/unbound/doc/unbound-anchor.8.in
usr.sbin/unbound/doc/unbound-checkconf.8.in
usr.sbin/unbound/doc/unbound-control.8.in
usr.sbin/unbound/doc/unbound-host.1.in
usr.sbin/unbound/doc/unbound.8.in
usr.sbin/unbound/doc/unbound.conf.5.in
usr.sbin/unbound/doc/unbound.doxygen
usr.sbin/unbound/edns-subnet/subnetmod.c
usr.sbin/unbound/ipsecmod/ipsecmod.c
usr.sbin/unbound/iterator/iter_delegpt.c
usr.sbin/unbound/iterator/iter_delegpt.h
usr.sbin/unbound/iterator/iter_fwd.c
usr.sbin/unbound/iterator/iter_hints.c
usr.sbin/unbound/iterator/iter_utils.c
usr.sbin/unbound/iterator/iter_utils.h
usr.sbin/unbound/iterator/iterator.c
usr.sbin/unbound/iterator/iterator.h
usr.sbin/unbound/libunbound/context.c
usr.sbin/unbound/libunbound/context.h
usr.sbin/unbound/libunbound/libunbound.c
usr.sbin/unbound/libunbound/libworker.c
usr.sbin/unbound/libunbound/unbound-event.h
usr.sbin/unbound/libunbound/unbound.h
usr.sbin/unbound/libunbound/worker.h
usr.sbin/unbound/respip/respip.c
usr.sbin/unbound/respip/respip.h
usr.sbin/unbound/services/authzone.c
usr.sbin/unbound/services/authzone.h
usr.sbin/unbound/services/cache/infra.c
usr.sbin/unbound/services/cache/infra.h
usr.sbin/unbound/services/cache/rrset.h
usr.sbin/unbound/services/listen_dnsport.c
usr.sbin/unbound/services/listen_dnsport.h
usr.sbin/unbound/services/localzone.c
usr.sbin/unbound/services/localzone.h
usr.sbin/unbound/services/mesh.c
usr.sbin/unbound/services/outside_network.c
usr.sbin/unbound/services/outside_network.h
usr.sbin/unbound/sldns/keyraw.c
usr.sbin/unbound/sldns/parseutil.h
usr.sbin/unbound/sldns/str2wire.c
usr.sbin/unbound/sldns/str2wire.h
usr.sbin/unbound/sldns/wire2str.c
usr.sbin/unbound/sldns/wire2str.h
usr.sbin/unbound/smallapp/unbound-anchor.c
usr.sbin/unbound/smallapp/unbound-checkconf.c
usr.sbin/unbound/smallapp/unbound-control.c
usr.sbin/unbound/smallapp/worker_cb.c
usr.sbin/unbound/util/config_file.c
usr.sbin/unbound/util/config_file.h
usr.sbin/unbound/util/configlexer.lex
usr.sbin/unbound/util/configparser.y
usr.sbin/unbound/util/data/msgencode.c
usr.sbin/unbound/util/data/msgparse.c
usr.sbin/unbound/util/data/msgparse.h
usr.sbin/unbound/util/data/msgreply.c
usr.sbin/unbound/util/data/msgreply.h
usr.sbin/unbound/util/data/packed_rrset.h
usr.sbin/unbound/util/fptr_wlist.c
usr.sbin/unbound/util/fptr_wlist.h
usr.sbin/unbound/util/iana_ports.inc
usr.sbin/unbound/util/mini_event.c
usr.sbin/unbound/util/module.h
usr.sbin/unbound/util/net_help.c
usr.sbin/unbound/util/net_help.h
usr.sbin/unbound/util/netevent.c
usr.sbin/unbound/util/netevent.h
usr.sbin/unbound/util/shm_side/shm_main.c
usr.sbin/unbound/util/tube.c
usr.sbin/unbound/util/ub_event.c
usr.sbin/unbound/validator/autotrust.c
usr.sbin/unbound/validator/val_utils.c
usr.sbin/unbound/validator/validator.c
usr.sbin/unbound/validator/validator.h

index 00c73b2..c3b113a 100644 (file)
@@ -61,6 +61,7 @@ PYTHON_CPPFLAGS=-I. @PYTHON_CPPFLAGS@
 CFLAGS=-DSRCDIR=$(srcdir) @CFLAGS@
 LDFLAGS=@LDFLAGS@
 LIBS=@LIBS@
+PYTHON_LIBS=@PYTHON_LIBS@
 LIBOBJS=@LIBOBJS@
 # filter out ctime_r from compat obj.
 LIBOBJ_WITHOUT_CTIME=@LIBOBJ_WITHOUT_CTIME@
@@ -85,6 +86,8 @@ LINTFLAGS+=@NETBSD_LINTFLAGS@
 LINTFLAGS+="-Dsigset_t=long"
 # FreeBSD
 LINTFLAGS+="-D__uint16_t=uint16_t" "-DEVP_PKEY_ASN1_METHOD=int" "-D_RuneLocale=int" "-D__va_list=va_list" "-D__uint32_t=uint32_t" "-D_Alignof(x)=x" "-D__aligned(x)=" "-D__requires_exclusive(x)=" "-D__requires_unlocked(x)=" "-D__locks_exclusive(x)=" "-D__trylocks_exclusive(x)="  "-D__unlocks(x)=" "-D__locks_shared(x)=" "-D__trylocks_shared(x)="
+# GCC Docker
+LINTFLAGS+=@GCC_DOCKER_LINTFLAGS@
 
 INSTALL=$(SHELL) $(srcdir)/install-sh
 
@@ -476,7 +479,7 @@ libunbound/python/libunbound_wrap.c:        $(srcdir)/libunbound/python/libunbound.i un
 
 # Pyunbound python unbound wrapper
 _unbound.la:   libunbound_wrap.lo libunbound.la
-       $(LIBTOOL) --tag=CC --mode=link $(CC) $(RUNTIME_PATH) $(CPPFLAGS) $(CFLAGS) $(LDFLAGS) -module -avoid-version -no-undefined -shared -o $@ libunbound_wrap.lo -rpath $(PYTHON_SITE_PKG) -L. -L.libs libunbound.la $(LIBS)
+       $(LIBTOOL) --tag=CC --mode=link $(CC) $(RUNTIME_PATH) $(CPPFLAGS) $(CFLAGS) $(LDFLAGS) -module -avoid-version -no-undefined -shared -o $@ libunbound_wrap.lo -rpath $(PYTHON_SITE_PKG) -L. -L.libs libunbound.la $(PYTHON_LIBS)
 
 util/config_file.c:    util/configparser.h
 util/configlexer.c:  $(srcdir)/util/configlexer.lex util/configparser.h
index 48497cb..d1bbcf2 100644 (file)
@@ -11,7 +11,7 @@ have any feedback, we would love to hear from you. Don’t hesitate to
 [create an issue on Github](https://github.com/NLnetLabs/unbound/issues/new)
 or post a message on the [Unbound mailing list](https://lists.nlnetlabs.nl/mailman/listinfo/unbound-users).
 You can learn more about Unbound by reading our
-[documentation](https://nlnetlabs.nl/documentation/unbound/).
+[documentation](https://unbound.docs.nlnetlabs.nl/).
 
 ## Compiling
 
@@ -33,44 +33,7 @@ support.
 
 All of Unbound's configuration options are described in the man pages, which
 will be installed and are available on the Unbound
-[documentation page](https://nlnetlabs.nl/documentation/unbound/).
-
-An example configuration file is located in
-[doc/example.conf](https://github.com/NLnetLabs/unbound/blob/master/doc/example.conf.in).
-# Unbound
-
-[![Travis Build Status](https://travis-ci.org/NLnetLabs/unbound.svg?branch=master)](https://travis-ci.org/NLnetLabs/unbound)
-[![Packaging status](https://repology.org/badge/tiny-repos/unbound.svg)](https://repology.org/project/unbound/versions)
-
-Unbound is a validating, recursive, caching DNS resolver. It is designed to be
-fast and lean and incorporates modern features based on open standards. If you
-have any feedback, we would love to hear from you. Don’t hesitate to
-[create an issue on Github](https://github.com/NLnetLabs/unbound/issues/new)
-or post a message on the [Unbound mailing list](https://nlnetlabs.nl/mailman/listinfo/unbound-users).
-You can lean more about Unbound by reading our
-[documentation](https://nlnetlabs.nl/documentation/unbound/).
-
-## Compiling
-
-Make sure you have the C toolchain, OpenSSL and its include files, and libexpat
-installed. Unbound can be compiled and installed using:
-
-```
-./configure && make && make install
-```
-
-You can use libevent if you want. libevent is useful when using many (10000)
-outgoing ports. By default max 256 ports are opened at the same time and the
-builtin alternative is equally capable and a little faster.
-
-Use the `--with-libevent=dir` configure option to compile Unbound with libevent
-support.
-
-## Unbound configuration
-
-All of Unbound's configuration options are described in the man pages, which
-will be installed and are available on the Unbound
-[documentation page](https://nlnetlabs.nl/documentation/unbound/).
+[documentation page](https://unbound.docs.nlnetlabs.nl/).
 
 An example configuration file is located in
 [doc/example.conf](https://github.com/NLnetLabs/unbound/blob/master/doc/example.conf.in).
index 39e92d8..1574f97 100644 (file)
@@ -2,7 +2,10 @@
 # Copyright 2009, Wouter Wijngaards, NLnet Labs.   
 # BSD licensed.
 #
-# Version 41
+# Version 43
+# 2021-08-17 fix sed script in ssldir split handling.
+# 2021-08-17 fix for openssl to detect split version, with ssldir_include
+#           and ssldir_lib output directories.
 # 2021-07-30 fix for openssl use of lib64 directory.
 # 2021-06-14 fix nonblocking test to use host instead of target for mingw test.
 # 2021-05-17 fix nonblocking socket test from grep on mingw32 to mingw for
@@ -647,6 +650,30 @@ AC_DEFUN([ACX_SSL_CHECKS], [
     withval=$1
     if test x_$withval != x_no; then
         AC_MSG_CHECKING(for SSL)
+       if test -n "$withval"; then
+               dnl look for openssl install with different version, eg.
+               dnl in /usr/include/openssl11/openssl/ssl.h
+               dnl and /usr/lib64/openssl11/libssl.so
+               dnl with the --with-ssl=/usr/include/openssl11
+               if test ! -f "$withval/include/openssl/ssl.h" -a -f "$withval/openssl/ssl.h"; then
+                       ssldir="$withval"
+                       found_ssl="yes"
+                       withval=""
+                       ssldir_include="$ssldir"
+                       dnl find the libdir
+                       ssldir_lib=`echo $ssldir | sed -e 's/include/lib/'`
+                       if test -f "$ssldir_lib/libssl.a" -o -f "$ssldir_lib/libssl.so"; then
+                               : # found here
+                       else
+                               ssldir_lib=`echo $ssldir | sed -e 's/include/lib64/'`
+                               if test -f "$ssldir_lib/libssl.a" -o -f "$ssldir_lib/libssl.so"; then
+                                       : # found here
+                               else
+                                       AC_MSG_ERROR([Could not find openssl lib file, $ssldir_lib/libssl.[so,a], pass like "/usr/local" or "/usr/include/openssl11"])
+                               fi
+                       fi
+               fi
+       fi
         if test x_$withval = x_ -o x_$withval = x_yes; then
             withval="/usr/local/ssl /usr/lib/ssl /usr/ssl /usr/pkg /usr/local /opt/local /usr/sfw /usr"
         fi
@@ -654,12 +681,12 @@ AC_DEFUN([ACX_SSL_CHECKS], [
             ssldir="$dir"
             if test -f "$dir/include/openssl/ssl.h"; then
                 found_ssl="yes"
-                AC_DEFINE_UNQUOTED([HAVE_SSL], [], [Define if you have the SSL libraries installed.])
-                dnl assume /usr/include is already in the include-path.
-                if test "$ssldir" != "/usr"; then
-                        CPPFLAGS="$CPPFLAGS -I$ssldir/include"
-                        LIBSSL_CPPFLAGS="$LIBSSL_CPPFLAGS -I$ssldir/include"
-                fi
+               ssldir_include="$ssldir/include"
+               if test ! -d "$ssldir/lib" -a -d "$ssldir/lib64"; then
+                       ssldir_lib="$ssldir/lib64"
+               else
+                       ssldir_lib="$ssldir/lib"
+               fi
                 break;
             fi
         done
@@ -667,19 +694,16 @@ AC_DEFUN([ACX_SSL_CHECKS], [
             AC_MSG_ERROR(Cannot find the SSL libraries in $withval)
         else
             AC_MSG_RESULT(found in $ssldir)
+            AC_DEFINE_UNQUOTED([HAVE_SSL], [], [Define if you have the SSL libraries installed.])
             HAVE_SSL=yes
-            dnl assume /usr is already in the lib and dynlib paths.
-            if test "$ssldir" != "/usr" -a "$ssldir" != ""; then
-               if test ! -d "$ssldir/lib" -a -d "$ssldir/lib64"; then
-                       LDFLAGS="$LDFLAGS -L$ssldir/lib64"
-                       LIBSSL_LDFLAGS="$LIBSSL_LDFLAGS -L$ssldir/lib64"
-                       ACX_RUNTIME_PATH_ADD([$ssldir/lib64])
-               else
-                       LDFLAGS="$LDFLAGS -L$ssldir/lib"
-                       LIBSSL_LDFLAGS="$LIBSSL_LDFLAGS -L$ssldir/lib"
-                       ACX_RUNTIME_PATH_ADD([$ssldir/lib])
-               fi
-            fi
+           dnl assume /usr is already in the include, lib and dynlib paths.
+            if test "$ssldir" != "/usr"; then
+                   CPPFLAGS="$CPPFLAGS -I$ssldir_include"
+                   LIBSSL_CPPFLAGS="$LIBSSL_CPPFLAGS -I$ssldir_include"
+                   LDFLAGS="$LDFLAGS -L$ssldir_lib"
+                   LIBSSL_LDFLAGS="$LIBSSL_LDFLAGS -L$ssldir_lib"
+                   ACX_RUNTIME_PATH_ADD([$ssldir_lib])
+           fi
         
             AC_MSG_CHECKING([for EVP_sha256 in -lcrypto])
             LIBS="$LIBS -lcrypto"
@@ -758,7 +782,7 @@ dnl
 AC_DEFUN([ACX_WITH_SSL],
 [
 AC_ARG_WITH(ssl, AS_HELP_STRING([--with-ssl=pathname],[enable SSL (will check /usr/local/ssl
-                            /usr/lib/ssl /usr/ssl /usr/pkg /usr/local /opt/local /usr/sfw /usr)]),[
+                            /usr/lib/ssl /usr/ssl /usr/pkg /usr/local /opt/local /usr/sfw /usr or specify like /usr/include/openssl11)]),[
         ],[
             withval="yes"
         ])
@@ -776,7 +800,7 @@ dnl
 AC_DEFUN([ACX_WITH_SSL_OPTIONAL],
 [
 AC_ARG_WITH(ssl, AS_HELP_STRING([--with-ssl=pathname],[enable SSL (will check /usr/local/ssl
-                                /usr/lib/ssl /usr/ssl /usr/pkg /usr/local /opt/local /usr/sfw /usr)]),[
+                                /usr/lib/ssl /usr/ssl /usr/pkg /usr/local /opt/local /usr/sfw /usr or specify like /usr/include/openssl11)]),[
         ],[
             withval="yes"
         ])
index af4ffe5..725bc6c 100644 (file)
@@ -519,7 +519,7 @@ parse_data(struct module_qstate* qstate, struct sldns_buffer* buf)
                sldns_buffer_set_limit(buf, lim);
                return 0;
        }
-       if(parse_extract_edns(prs, &edns, qstate->env->scratch) !=
+       if(parse_extract_edns_from_response_msg(prs, &edns, qstate->env->scratch) !=
                LDNS_RCODE_NOERROR) {
                sldns_buffer_set_limit(buf, lim);
                return 0;
index e81d3ae..7f76b62 100644 (file)
@@ -1,14 +1,14 @@
 #! /bin/sh
 # Attempt to guess a canonical system name.
-#   Copyright 1992-2021 Free Software Foundation, Inc.
+#   Copyright 1992-2022 Free Software Foundation, Inc.
 
 # shellcheck disable=SC2006,SC2268 # see below for rationale
 
-timestamp='2021-06-03'
+timestamp='2022-01-09'
 
 # 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
-# the Free Software Foundation; either version 3 of the License, or
+# the Free Software Foundation, either version 3 of the License, or
 # (at your option) any later version.
 #
 # This program is distributed in the hope that it will be useful, but
@@ -60,7 +60,7 @@ version="\
 GNU config.guess ($timestamp)
 
 Originally written by Per Bothner.
-Copyright 1992-2021 Free Software Foundation, Inc.
+Copyright 1992-2022 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."
@@ -437,7 +437,7 @@ case $UNAME_MACHINE:$UNAME_SYSTEM:$UNAME_RELEASE:$UNAME_VERSION in
        # This test works for both compilers.
        if test "$CC_FOR_BUILD" != no_compiler_found; then
            if (echo '#ifdef __amd64'; echo IS_64BIT_ARCH; echo '#endif') | \
-               (CCOPTS="" $CC_FOR_BUILD -E - 2>/dev/null) | \
+               (CCOPTS="" $CC_FOR_BUILD -m64 -E - 2>/dev/null) | \
                grep IS_64BIT_ARCH >/dev/null
            then
                SUN_ARCH=x86_64
@@ -929,6 +929,9 @@ EOF
     i*:PW*:*)
        GUESS=$UNAME_MACHINE-pc-pw32
        ;;
+    *:SerenityOS:*:*)
+        GUESS=$UNAME_MACHINE-pc-serenity
+        ;;
     *:Interix*:*)
        case $UNAME_MACHINE in
            x86)
@@ -1522,6 +1525,9 @@ EOF
     i*86:rdos:*:*)
        GUESS=$UNAME_MACHINE-pc-rdos
        ;;
+    i*86:Fiwix:*:*)
+       GUESS=$UNAME_MACHINE-pc-fiwix
+       ;;
     *:AROS:*:*)
        GUESS=$UNAME_MACHINE-unknown-aros
        ;;
index ca2dfad..8edb691 100644 (file)
@@ -72,6 +72,9 @@
 /* If we have be64toh */
 #undef HAVE_BE64TOH
 
+/* Define to 1 if you have the `BIO_set_callback_ex' function. */
+#undef HAVE_BIO_SET_CALLBACK_EX
+
 /* Define to 1 if you have the <bsd/stdlib.h> header file. */
 #undef HAVE_BSD_STDLIB_H
 
 /* Define to 1 if you have the `if_nametoindex' function. */
 #undef HAVE_IF_NAMETOINDEX
 
+/* Define to 1 if you have the `if_nametoindex' function. */
+#undef HAVE_IF_NAMETOINDEX
+
 /* Define to 1 if you have the `inet_aton' function. */
 #undef HAVE_INET_ATON
 
 /* Define to 1 if you have the <netinet/tcp.h> header file. */
 #undef HAVE_NETINET_TCP_H
 
+/* Define to 1 if you have the <netioapi.h> header file. */
+#undef HAVE_NETIOAPI_H
+
 /* Use libnettle for crypto */
 #undef HAVE_NETTLE
 
index d80c5d7..dba16e8 100644 (file)
@@ -1,14 +1,14 @@
 #! /bin/sh
 # Configuration validation subroutine script.
-#   Copyright 1992-2021 Free Software Foundation, Inc.
+#   Copyright 1992-2022 Free Software Foundation, Inc.
 
 # shellcheck disable=SC2006,SC2268 # see below for rationale
 
-timestamp='2021-07-03'
+timestamp='2022-01-03'
 
 # 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
-# the Free Software Foundation; either version 3 of the License, or
+# the Free Software Foundation, either version 3 of the License, or
 # (at your option) any later version.
 #
 # This program is distributed in the hope that it will be useful, but
@@ -76,7 +76,7 @@ Report bugs and patches to <config-patches@gnu.org>."
 version="\
 GNU config.sub ($timestamp)
 
-Copyright 1992-2021 Free Software Foundation, Inc.
+Copyright 1992-2022 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."
@@ -121,9 +121,11 @@ esac
 
 # Split fields of configuration type
 # shellcheck disable=SC2162
+saved_IFS=$IFS
 IFS="-" read field1 field2 field3 field4 <<EOF
 $1
 EOF
+IFS=$saved_IFS
 
 # Separate into logical components for further validation
 case $1 in
@@ -172,6 +174,10 @@ case $1 in
                                                basic_machine=$field1
                                                basic_os=$field2
                                                ;;
+                                       zephyr*)
+                                               basic_machine=$field1-unknown
+                                               basic_os=$field2
+                                               ;;
                                        # Manufacturers
                                        dec* | mips* | sequent* | encore* | pc533* | sgi* | sony* \
                                        | att* | 7300* | 3300* | delta* | motorola* | sun[234]* \
@@ -931,9 +937,11 @@ case $basic_machine in
 
        *-*)
                # shellcheck disable=SC2162
+               saved_IFS=$IFS
                IFS="-" read cpu vendor <<EOF
 $basic_machine
 EOF
+               IFS=$saved_IFS
                ;;
        # We use `pc' rather than `unknown'
        # because (1) that's what they normally are, and
@@ -1012,6 +1020,11 @@ case $cpu-$vendor in
                ;;
 
        # Here we normalize CPU types with a missing or matching vendor
+       armh-unknown | armh-alt)
+               cpu=armv7l
+               vendor=alt
+               basic_os=${basic_os:-linux-gnueabihf}
+               ;;
        dpx20-unknown | dpx20-bull)
                cpu=rs6000
                vendor=bull
@@ -1113,7 +1126,7 @@ case $cpu-$vendor in
        xscale-* | xscalee[bl]-*)
                cpu=`echo "$cpu" | sed 's/^xscale/arm/'`
                ;;
-       arm64-*)
+       arm64-* | aarch64le-*)
                cpu=aarch64
                ;;
 
@@ -1296,7 +1309,7 @@ esac
 if test x$basic_os != x
 then
 
-# First recognize some ad-hoc caes, or perhaps split kernel-os, or else just
+# First recognize some ad-hoc cases, or perhaps split kernel-os, or else just
 # set os.
 case $basic_os in
        gnu/linux*)
@@ -1313,9 +1326,11 @@ case $basic_os in
                ;;
        *-*)
                # shellcheck disable=SC2162
+               saved_IFS=$IFS
                IFS="-" read kernel os <<EOF
 $basic_os
 EOF
+               IFS=$saved_IFS
                ;;
        # Default OS when just kernel was specified
        nto*)
@@ -1697,7 +1712,7 @@ fi
 # Now, validate our (potentially fixed-up) OS.
 case $os in
        # Sometimes we do "kernel-libc", so those need to count as OSes.
-       musl* | newlib* | uclibc*)
+       musl* | newlib* | relibc* | uclibc*)
                ;;
        # Likewise for "kernel-abi"
        eabi* | gnueabi*)
@@ -1738,7 +1753,8 @@ case $os in
             | skyos* | haiku* | rdos* | toppers* | drops* | es* \
             | onefs* | tirtos* | phoenix* | fuchsia* | redox* | bme* \
             | midnightbsd* | amdhsa* | unleashed* | emscripten* | wasi* \
-            | nsk* | powerunix* | genode* | zvmoe* | qnx* | emx*)
+            | nsk* | powerunix* | genode* | zvmoe* | qnx* | emx* | zephyr* \
+            | fiwix* )
                ;;
        # This one is extra strict with allowed versions
        sco3.2v2 | sco3.2v[4-9]* | sco5v6*)
@@ -1755,11 +1771,12 @@ 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 in
-       linux-gnu* | linux-dietlibc* | linux-android* | linux-newlib* | linux-musl* | linux-uclibc* )
+       linux-gnu* | linux-dietlibc* | linux-android* | linux-newlib* \
+                  | linux-musl* | linux-relibc* | linux-uclibc* )
                ;;
        uclinux-uclibc* )
                ;;
-       -dietlibc* | -newlib* | -musl* | -uclibc* )
+       -dietlibc* | -newlib* | -musl* | -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
index 0362aee..350cd5a 100644 (file)
@@ -1,6 +1,6 @@
 #! /bin/sh
 # Guess values for system-dependent variables and create Makefiles.
-# Generated by GNU Autoconf 2.71 for unbound 1.13.2.
+# Generated by GNU Autoconf 2.71 for unbound 1.15.0.
 #
 # Report bugs to <unbound-bugs@nlnetlabs.nl or https://github.com/NLnetLabs/unbound/issues>.
 #
@@ -622,8 +622,8 @@ MAKEFLAGS=
 # Identity of this package.
 PACKAGE_NAME='unbound'
 PACKAGE_TARNAME='unbound'
-PACKAGE_VERSION='1.13.2'
-PACKAGE_STRING='unbound 1.13.2'
+PACKAGE_VERSION='1.15.0'
+PACKAGE_STRING='unbound 1.15.0'
 PACKAGE_BUGREPORT='unbound-bugs@nlnetlabs.nl or https://github.com/NLnetLabs/unbound/issues'
 PACKAGE_URL=''
 
@@ -710,6 +710,7 @@ SSLLIB
 HAVE_SSL
 PC_CRYPTO_DEPENDENCY
 CONFIG_DATE
+GCC_DOCKER_LINTFLAGS
 NETBSD_LINTFLAGS
 PYUNBOUND_UNINSTALL
 PYUNBOUND_INSTALL
@@ -725,6 +726,7 @@ swig
 SWIG_LIB
 SWIG
 PC_PY_DEPENDENCY
+PYTHON_LIBS
 PY_MAJOR_VERSION
 PYTHON_SITE_PKG
 PYTHON_LDFLAGS
@@ -1501,7 +1503,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.13.2 to adapt to many kinds of systems.
+\`configure' configures unbound 1.15.0 to adapt to many kinds of systems.
 
 Usage: $0 [OPTION]... [VAR=VALUE]...
 
@@ -1567,7 +1569,7 @@ fi
 
 if test -n "$ac_init_help"; then
   case $ac_init_help in
-     short | recursive ) echo "Configuration of unbound 1.13.2:";;
+     short | recursive ) echo "Configuration of unbound 1.15.0:";;
    esac
   cat <<\_ACEOF
 
@@ -1687,7 +1689,7 @@ Optional Packages:
   --with-nettle=path      use libnettle as crypto library, installed at path.
   --with-ssl=pathname     enable SSL (will check /usr/local/ssl /usr/lib/ssl
                           /usr/ssl /usr/pkg /usr/local /opt/local /usr/sfw
-                          /usr)
+                          /usr or specify like /usr/include/openssl11)
   --with-libbsd           Use portable libbsd functions
   --with-deprecate-rsa-1024
                           Deprecate RSA 1024 bit length, makes that an
@@ -1810,7 +1812,7 @@ fi
 test -n "$ac_init_help" && exit $ac_status
 if $ac_init_version; then
   cat <<\_ACEOF
-unbound configure 1.13.2
+unbound configure 1.15.0
 generated by GNU Autoconf 2.71
 
 Copyright (C) 2021 Free Software Foundation, Inc.
@@ -2467,7 +2469,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.13.2, which was
+It was created by unbound $as_me 1.15.0, which was
 generated by GNU Autoconf 2.71.  Invocation command line was
 
   $ $0$ac_configure_args_raw
@@ -3229,13 +3231,13 @@ ac_compiler_gnu=$ac_cv_c_compiler_gnu
 
 UNBOUND_VERSION_MAJOR=1
 
-UNBOUND_VERSION_MINOR=13
+UNBOUND_VERSION_MINOR=15
 
-UNBOUND_VERSION_MICRO=2
+UNBOUND_VERSION_MICRO=0
 
 
 LIBUNBOUND_CURRENT=9
-LIBUNBOUND_REVISION=13
+LIBUNBOUND_REVISION=15
 LIBUNBOUND_AGE=1
 # 1.0.0 had 0:12:0
 # 1.0.1 had 0:13:0
@@ -3316,6 +3318,8 @@ LIBUNBOUND_AGE=1
 # 1.13.0 had 9:11:1
 # 1.13.1 had 9:12:1
 # 1.13.2 had 9:13:1
+# 1.14.0 had 9:14:1
+# 1.15.0 had 9:15:1
 
 #   Current  -- the number of the binary API that we're implementing
 #   Revision -- which iteration of the implementation of the binary
@@ -15916,6 +15920,46 @@ then :
 
 fi
 
+ac_fn_c_check_header_compile "$LINENO" "netioapi.h" "ac_cv_header_netioapi_h" "$ac_includes_default
+#if HAVE_SYS_PARAM_H
+#include <sys/param.h>
+#endif
+
+#ifdef HAVE_SYS_SOCKET_H
+#include <sys/socket.h>
+#endif
+
+#ifdef HAVE_SYS_UIO_H
+#include <sys/uio.h>
+#endif
+
+#ifdef HAVE_NETINET_IN_H
+#include <netinet/in.h>
+#endif
+
+#ifdef HAVE_NETINET_TCP_H
+#include <netinet/tcp.h>
+#endif
+
+#ifdef HAVE_ARPA_INET_H
+#include <arpa/inet.h>
+#endif
+
+#ifdef HAVE_WINSOCK2_H
+#include <winsock2.h>
+#endif
+
+#ifdef HAVE_WS2TCPIP_H
+#include <ws2tcpip.h>
+#endif
+
+"
+if test "x$ac_cv_header_netioapi_h" = xyes
+then :
+  printf "%s\n" "#define HAVE_NETIOAPI_H 1" >>confdefs.h
+
+fi
+
 
 # check for types.
 # Using own tests for int64* because autoconf builtin only give 32bit.
@@ -16593,7 +16637,7 @@ then :
 fi
 
 
-# check wether strptime also works
+# check whether strptime also works
 
 # check some functions of the OS before linking libs (while still runnable).
 { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for working chown" >&5
@@ -17499,6 +17543,7 @@ fi
 
 done
 
+
 # check if we can use SO_REUSEPORT
 reuseport_default=0
 if echo "$host" | $GREP -i -e linux >/dev/null; then reuseport_default=1; fi
@@ -18873,11 +18918,15 @@ ac_compiler_gnu=$ac_cv_c_compiler_gnu
 
 printf "%s\n" "#define HAVE_PYTHON 1" >>confdefs.h
 
-      if test -n "$LIBS"; then
-        LIBS="$PYTHON_LDFLAGS $LIBS"
-      else
-        LIBS="$PYTHON_LDFLAGS"
+      if test x_$ub_with_pythonmod != x_no; then
+        if test -n "$LIBS"; then
+          LIBS="$PYTHON_LDFLAGS $LIBS"
+        else
+          LIBS="$PYTHON_LDFLAGS"
+        fi
       fi
+      PYTHON_LIBS="$PYTHON_LDFLAGS"
+
       if test -n "$CPPFLAGS"; then
         CPPFLAGS="$CPPFLAGS $PYTHON_CPPFLAGS"
       else
 if test "`uname`" = "NetBSD"; then
        NETBSD_LINTFLAGS='"-D__RENAME(x)=" -D_NETINET_IN_H_'
 
+fi
+
+if test "`uname`" = "Linux"; then
+       # splint cannot parse modern c99 header files
+       GCC_DOCKER_LINTFLAGS='-syntax'
+
 fi
 CONFIG_DATE=`date +%Y%m%d`
 
     if test x_$withval != x_no; then
         { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for SSL" >&5
 printf %s "checking for SSL... " >&6; }
+       if test -n "$withval"; then
+                                                                               if test ! -f "$withval/include/openssl/ssl.h" -a -f "$withval/openssl/ssl.h"; then
+                       ssldir="$withval"
+                       found_ssl="yes"
+                       withval=""
+                       ssldir_include="$ssldir"
+                                               ssldir_lib=`echo $ssldir | sed -e 's/include/lib/'`
+                       if test -f "$ssldir_lib/libssl.a" -o -f "$ssldir_lib/libssl.so"; then
+                               : # found here
+                       else
+                               ssldir_lib=`echo $ssldir | sed -e 's/include/lib64/'`
+                               if test -f "$ssldir_lib/libssl.a" -o -f "$ssldir_lib/libssl.so"; then
+                                       : # found here
+                               else
+                                       as_fn_error $? "Could not find openssl lib file, $ssldir_lib/libssl.so,a, pass like \"/usr/local\" or \"/usr/include/openssl11\"" "$LINENO" 5
+                               fi
+                       fi
+               fi
+       fi
         if test x_$withval = x_ -o x_$withval = x_yes; then
             withval="/usr/local/ssl /usr/lib/ssl /usr/ssl /usr/pkg /usr/local /opt/local /usr/sfw /usr"
         fi
@@ -19329,13 +19403,12 @@ printf %s "checking for SSL... " >&6; }
             ssldir="$dir"
             if test -f "$dir/include/openssl/ssl.h"; then
                 found_ssl="yes"
-
-printf "%s\n" "#define HAVE_SSL /**/" >>confdefs.h
-
-                                if test "$ssldir" != "/usr"; then
-                        CPPFLAGS="$CPPFLAGS -I$ssldir/include"
-                        LIBSSL_CPPFLAGS="$LIBSSL_CPPFLAGS -I$ssldir/include"
-                fi
+               ssldir_include="$ssldir/include"
+               if test ! -d "$ssldir/lib" -a -d "$ssldir/lib64"; then
+                       ssldir_lib="$ssldir/lib64"
+               else
+                       ssldir_lib="$ssldir/lib"
+               fi
                 break;
             fi
         done
@@ -19344,30 +19417,23 @@ printf "%s\n" "#define HAVE_SSL /**/" >>confdefs.h
         else
             { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: found in $ssldir" >&5
 printf "%s\n" "found in $ssldir" >&6; }
-            HAVE_SSL=yes
-                        if test "$ssldir" != "/usr" -a "$ssldir" != ""; then
-               if test ! -d "$ssldir/lib" -a -d "$ssldir/lib64"; then
-                       LDFLAGS="$LDFLAGS -L$ssldir/lib64"
-                       LIBSSL_LDFLAGS="$LIBSSL_LDFLAGS -L$ssldir/lib64"
 
-       if test "x$enable_rpath" = xyes; then
-               if echo "$ssldir/lib64" | grep "^/" >/dev/null; then
-                       RUNTIME_PATH="$RUNTIME_PATH -R$ssldir/lib64"
-               fi
-       fi
+printf "%s\n" "#define HAVE_SSL /**/" >>confdefs.h
 
-               else
-                       LDFLAGS="$LDFLAGS -L$ssldir/lib"
-                       LIBSSL_LDFLAGS="$LIBSSL_LDFLAGS -L$ssldir/lib"
+            HAVE_SSL=yes
+                       if test "$ssldir" != "/usr"; then
+                   CPPFLAGS="$CPPFLAGS -I$ssldir_include"
+                   LIBSSL_CPPFLAGS="$LIBSSL_CPPFLAGS -I$ssldir_include"
+                   LDFLAGS="$LDFLAGS -L$ssldir_lib"
+                   LIBSSL_LDFLAGS="$LIBSSL_LDFLAGS -L$ssldir_lib"
 
        if test "x$enable_rpath" = xyes; then
-               if echo "$ssldir/lib" | grep "^/" >/dev/null; then
-                       RUNTIME_PATH="$RUNTIME_PATH -R$ssldir/lib"
+               if echo "$ssldir_lib" | grep "^/" >/dev/null; then
+                       RUNTIME_PATH="$RUNTIME_PATH -R$ssldir_lib"
                fi
        fi
 
-               fi
-            fi
+           fi
 
             { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for EVP_sha256 in -lcrypto" >&5
 printf %s "checking for EVP_sha256 in -lcrypto... " >&6; }
@@ -19645,7 +19711,7 @@ rm -f core conftest.err conftest.$ac_objext conftest.beam \
     conftest$ac_exeext conftest.$ac_ext
 SSLLIB="-lssl"
 
-PC_CRYPTO_DEPENDENCY="libcrypto libssl"
+PC_CRYPTO_DEPENDENCY=""
 
 
 # check if -lcrypt32 is needed because CAPIENG needs that. (on windows)
@@ -19687,7 +19753,7 @@ rm -f core conftest.err conftest.$ac_objext conftest.beam \
 
 { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for LibreSSL" >&5
 printf %s "checking for LibreSSL... " >&6; }
-if grep VERSION_TEXT $ssldir/include/openssl/opensslv.h | grep "LibreSSL" >/dev/null; then
+if grep VERSION_TEXT $ssldir_include/openssl/opensslv.h | grep "LibreSSL" >/dev/null; then
        { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: yes" >&5
 printf "%s\n" "yes" >&6; }
 
@@ -20007,6 +20073,12 @@ then :
   printf "%s\n" "#define HAVE_OSSL_PARAM_BLD_NEW 1" >>confdefs.h
 
 fi
+ac_fn_c_check_func "$LINENO" "BIO_set_callback_ex" "ac_cv_func_BIO_set_callback_ex"
+if test "x$ac_cv_func_BIO_set_callback_ex" = xyes
+then :
+  printf "%s\n" "#define HAVE_BIO_SET_CALLBACK_EX 1" >>confdefs.h
+
+fi
 
 
 # these check_funcs need -lssl
@@ -20376,7 +20448,7 @@ printf "%s\n" "#define CLIENT_SUBNET 1" >>confdefs.h
        ;;
 esac
 
-# check wether gost also works
+# check whether gost also works
 
 # Check whether --enable-gost was given.
 if test ${enable_gost+y}
@@ -20412,7 +20484,7 @@ printf %s "checking if GOST works... " >&6; }
 if test c${cross_compiling} = cno; then
 BAKCFLAGS="$CFLAGS"
 if test -n "$ssldir"; then
-       CFLAGS="$CFLAGS -Wl,-rpath,$ssldir/lib"
+       CFLAGS="$CFLAGS -Wl,-rpath,$ssldir_lib"
 fi
 if test "$cross_compiling" = yes
 then :
@@ -20598,8 +20670,8 @@ fi
              # see if OPENSSL 1.0.0 or later (has EVP MD and Verify independency)
              { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking if openssl supports SHA2 and ECDSA with EVP" >&5
 printf %s "checking if openssl supports SHA2 and ECDSA with EVP... " >&6; }
-             if grep OPENSSL_VERSION_TEXT $ssldir/include/openssl/opensslv.h | grep "OpenSSL" >/dev/null; then
-               if grep OPENSSL_VERSION_NUMBER $ssldir/include/openssl/opensslv.h | grep 0x0 >/dev/null; then
+             if grep OPENSSL_VERSION_TEXT $ssldir_include/openssl/opensslv.h | grep "OpenSSL" >/dev/null; then
+               if grep OPENSSL_VERSION_NUMBER $ssldir_include/openssl/opensslv.h | grep 0x0 >/dev/null; then
                  { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5
 printf "%s\n" "no" >&6; }
 
@@ -22160,6 +22232,12 @@ if test "x$ac_cv_func_getifaddrs" = xyes
 then :
   printf "%s\n" "#define HAVE_GETIFADDRS 1" >>confdefs.h
 
+fi
+ac_fn_c_check_func "$LINENO" "if_nametoindex" "ac_cv_func_if_nametoindex"
+if test "x$ac_cv_func_if_nametoindex" = xyes
+then :
+  printf "%s\n" "#define HAVE_IF_NAMETOINDEX 1" >>confdefs.h
+
 fi
 
 
@@ -23475,12 +23553,6 @@ then :
                INSTALLTARGET="install-lib"
        fi
 
-fi
-ac_fn_c_check_func "$LINENO" "if_nametoindex" "ac_cv_func_if_nametoindex"
-if test "x$ac_cv_func_if_nametoindex" = xyes
-then :
-  printf "%s\n" "#define HAVE_IF_NAMETOINDEX 1" >>confdefs.h
-
 fi
 
 if test $ALLTARGET = "alltargets"; then
@@ -23584,7 +23656,7 @@ printf "%s\n" "#define MAXSYSLOGMSGLEN 10240" >>confdefs.h
 
 
 
-version=1.13.2
+version=1.15.0
 
 date=`date +'%b %e, %Y'`
 
@@ -24096,7 +24168,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.13.2, which was
+This file was extended by unbound $as_me 1.15.0, which was
 generated by GNU Autoconf 2.71.  Invocation command line was
 
   CONFIG_FILES    = $CONFIG_FILES
@@ -24164,7 +24236,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.13.2
+unbound config.status 1.15.0
 configured by $0, generated by GNU Autoconf 2.71,
   with options \\"\$ac_cs_config\\"
 
index ea25c8a..80f3f5c 100644 (file)
@@ -10,15 +10,15 @@ sinclude(dnscrypt/dnscrypt.m4)
 
 # must be numbers. ac_defun because of later processing
 m4_define([VERSION_MAJOR],[1])
-m4_define([VERSION_MINOR],[13])
-m4_define([VERSION_MICRO],[2])
+m4_define([VERSION_MINOR],[15])
+m4_define([VERSION_MICRO],[0])
 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=13
+LIBUNBOUND_REVISION=15
 LIBUNBOUND_AGE=1
 # 1.0.0 had 0:12:0
 # 1.0.1 had 0:13:0
@@ -99,6 +99,8 @@ LIBUNBOUND_AGE=1
 # 1.13.0 had 9:11:1
 # 1.13.1 had 9:12:1
 # 1.13.2 had 9:13:1
+# 1.14.0 had 9:14:1
+# 1.15.0 had 9:15:1
 
 #   Current  -- the number of the binary API that we're implementing
 #   Revision -- which iteration of the implementation of the binary
@@ -411,6 +413,39 @@ AC_CHECK_HEADERS([net/if.h],,, [
 
 # Check for Apple header. This uncovers TARGET_OS_IPHONE, TARGET_OS_TV or TARGET_OS_WATCH
 AC_CHECK_HEADERS([TargetConditionals.h],,, [AC_INCLUDES_DEFAULT])
+AC_CHECK_HEADERS([netioapi.h],,, [AC_INCLUDES_DEFAULT
+#if HAVE_SYS_PARAM_H
+#include <sys/param.h>
+#endif
+
+#ifdef HAVE_SYS_SOCKET_H
+#include <sys/socket.h>
+#endif
+
+#ifdef HAVE_SYS_UIO_H
+#include <sys/uio.h>
+#endif
+
+#ifdef HAVE_NETINET_IN_H
+#include <netinet/in.h>
+#endif
+
+#ifdef HAVE_NETINET_TCP_H
+#include <netinet/tcp.h>
+#endif
+
+#ifdef HAVE_ARPA_INET_H
+#include <arpa/inet.h>
+#endif
+
+#ifdef HAVE_WINSOCK2_H
+#include <winsock2.h>
+#endif
+
+#ifdef HAVE_WS2TCPIP_H
+#include <ws2tcpip.h>
+#endif
+])
 
 # check for types.  
 # Using own tests for int64* because autoconf builtin only give 32bit.
@@ -457,7 +492,7 @@ AC_SUBST(RUNTIME_PATH)
 AC_SEARCH_LIBS([inet_pton], [nsl])
 AC_SEARCH_LIBS([socket], [socket])
 
-# check wether strptime also works
+# check whether strptime also works
 AC_DEFUN([AC_CHECK_STRPTIME_WORKS],
 [AC_REQUIRE([AC_PROG_CC])
 AC_MSG_CHECKING(whether strptime works)
@@ -492,6 +527,7 @@ ACX_CHECK_NONBLOCKING_BROKEN
 ACX_MKDIR_ONE_ARG
 AC_CHECK_FUNCS([strptime],[AC_CHECK_STRPTIME_WORKS],[AC_LIBOBJ([strptime])])
 
+
 # check if we can use SO_REUSEPORT
 reuseport_default=0
 if echo "$host" | $GREP -i -e linux >/dev/null; then reuseport_default=1; fi
@@ -699,11 +735,15 @@ if test x_$ub_test_python != x_no; then
       AC_SUBST(PY_MAJOR_VERSION)
       # Have Python
       AC_DEFINE(HAVE_PYTHON,1,[Define if you have Python libraries and header files.])
-      if test -n "$LIBS"; then
-        LIBS="$PYTHON_LDFLAGS $LIBS"
-      else
-        LIBS="$PYTHON_LDFLAGS"
+      if test x_$ub_with_pythonmod != x_no; then
+        if test -n "$LIBS"; then
+          LIBS="$PYTHON_LDFLAGS $LIBS"
+        else
+          LIBS="$PYTHON_LDFLAGS"
+        fi
       fi
+      PYTHON_LIBS="$PYTHON_LDFLAGS"
+      AC_SUBST(PYTHON_LIBS)
       if test -n "$CPPFLAGS"; then
         CPPFLAGS="$CPPFLAGS $PYTHON_CPPFLAGS"
       else
@@ -776,6 +816,12 @@ if test "`uname`" = "NetBSD"; then
        NETBSD_LINTFLAGS='"-D__RENAME(x)=" -D_NETINET_IN_H_'
        AC_SUBST(NETBSD_LINTFLAGS)
 fi
+
+if test "`uname`" = "Linux"; then
+       # splint cannot parse modern c99 header files
+       GCC_DOCKER_LINTFLAGS='-syntax'
+       AC_SUBST(GCC_DOCKER_LINTFLAGS)
+fi
 CONFIG_DATE=`date +%Y%m%d`
 AC_SUBST(CONFIG_DATE)
 
@@ -830,7 +876,7 @@ ACX_WITH_SSL
 ACX_LIB_SSL
 SSLLIB="-lssl"
 
-PC_CRYPTO_DEPENDENCY="libcrypto libssl"
+PC_CRYPTO_DEPENDENCY=""
 AC_SUBST(PC_CRYPTO_DEPENDENCY)
 
 # check if -lcrypt32 is needed because CAPIENG needs that. (on windows)
@@ -850,7 +896,7 @@ AC_LINK_IFELSE([AC_LANG_PROGRAM([[]], [[
 ])
 
 AC_MSG_CHECKING([for LibreSSL])
-if grep VERSION_TEXT $ssldir/include/openssl/opensslv.h | grep "LibreSSL" >/dev/null; then
+if grep VERSION_TEXT $ssldir_include/openssl/opensslv.h | grep "LibreSSL" >/dev/null; then
        AC_MSG_RESULT([yes])
        AC_DEFINE([HAVE_LIBRESSL], [1], [Define if we have LibreSSL])
        # libressl provides these compat functions, but they may also be
@@ -860,7 +906,7 @@ else
        AC_MSG_RESULT([no])
 fi
 AC_CHECK_HEADERS([openssl/conf.h openssl/engine.h openssl/bn.h openssl/dh.h openssl/dsa.h openssl/rsa.h openssl/core_names.h openssl/param_build.h],,, [AC_INCLUDES_DEFAULT])
-AC_CHECK_FUNCS([OPENSSL_config EVP_sha1 EVP_sha256 EVP_sha512 FIPS_mode EVP_MD_CTX_new OpenSSL_add_all_digests OPENSSL_init_crypto EVP_cleanup ENGINE_cleanup ERR_load_crypto_strings CRYPTO_cleanup_all_ex_data ERR_free_strings RAND_cleanup DSA_SIG_set0 EVP_dss1 EVP_DigestVerify EVP_aes_256_cbc EVP_EncryptInit_ex HMAC_Init_ex CRYPTO_THREADID_set_callback EVP_MAC_CTX_set_params OSSL_PARAM_BLD_new])
+AC_CHECK_FUNCS([OPENSSL_config EVP_sha1 EVP_sha256 EVP_sha512 FIPS_mode EVP_MD_CTX_new OpenSSL_add_all_digests OPENSSL_init_crypto EVP_cleanup ENGINE_cleanup ERR_load_crypto_strings CRYPTO_cleanup_all_ex_data ERR_free_strings RAND_cleanup DSA_SIG_set0 EVP_dss1 EVP_DigestVerify EVP_aes_256_cbc EVP_EncryptInit_ex HMAC_Init_ex CRYPTO_THREADID_set_callback EVP_MAC_CTX_set_params OSSL_PARAM_BLD_new BIO_set_callback_ex])
 
 # these check_funcs need -lssl
 BAKLIBS="$LIBS"
@@ -973,14 +1019,14 @@ case "$enable_subnet" in
        ;;
 esac
 
-# check wether gost also works
+# check whether gost also works
 AC_DEFUN([AC_CHECK_GOST_WORKS],
 [AC_REQUIRE([AC_PROG_CC])
 AC_MSG_CHECKING([if GOST works])
 if test c${cross_compiling} = cno; then
 BAKCFLAGS="$CFLAGS"
 if test -n "$ssldir"; then
-       CFLAGS="$CFLAGS -Wl,-rpath,$ssldir/lib"
+       CFLAGS="$CFLAGS -Wl,-rpath,$ssldir_lib"
 fi
 AC_RUN_IFELSE([AC_LANG_SOURCE([[
 #include <string.h>
@@ -1103,8 +1149,8 @@ case "$enable_ecdsa" in
              ])
              # see if OPENSSL 1.0.0 or later (has EVP MD and Verify independency)
              AC_MSG_CHECKING([if openssl supports SHA2 and ECDSA with EVP])
-             if grep OPENSSL_VERSION_TEXT $ssldir/include/openssl/opensslv.h | grep "OpenSSL" >/dev/null; then
-               if grep OPENSSL_VERSION_NUMBER $ssldir/include/openssl/opensslv.h | grep 0x0 >/dev/null; then
+             if grep OPENSSL_VERSION_TEXT $ssldir_include/openssl/opensslv.h | grep "OpenSSL" >/dev/null; then
+               if grep OPENSSL_VERSION_NUMBER $ssldir_include/openssl/opensslv.h | grep 0x0 >/dev/null; then
                  AC_MSG_RESULT([no])
                  AC_DEFINE_UNQUOTED([USE_ECDSA_EVP_WORKAROUND], [1], [Define this to enable an EVP workaround for older openssl])
                else
index 6d66678..0e3923b 100644 (file)
@@ -210,7 +210,6 @@ daemon_init(void)
        }
 #endif /* USE_WINSOCK */
        signal_handling_record();
-       checklock_start();
 #ifdef HAVE_SSL
 #  ifdef HAVE_ERR_LOAD_CRYPTO_STRINGS
        ERR_load_crypto_strings();
@@ -280,6 +279,7 @@ daemon_init(void)
                free(daemon);
                return NULL;
        }
+       listen_setup_locks();
        if(gettimeofday(&daemon->time_boot, NULL) < 0)
                log_err("gettimeofday: %s", strerror(errno));
        daemon->time_last_stat = daemon->time_boot;
@@ -781,6 +781,7 @@ daemon_delete(struct daemon* daemon)
        alloc_clear(&daemon->superalloc);
        acl_list_delete(daemon->acl);
        tcl_list_delete(daemon->tcl);
+       listen_desetup_locks();
        free(daemon->chroot);
        free(daemon->pidfile);
        free(daemon->env);
index 923ddef..675ef43 100644 (file)
@@ -300,6 +300,7 @@ add_open(const char* ip, int nr, struct listen_port** list, int noproto_is_err,
                 */
                if(fd != -1) {
 #ifdef HAVE_CHOWN
+                       chmod(ip, (mode_t)(S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP));
                        if (cfg->username && cfg->username[0] &&
                                cfg_uid != (uid_t)-1) {
                                if(chown(ip, cfg_uid, cfg_gid) == -1)
@@ -307,7 +308,6 @@ add_open(const char* ip, int nr, struct listen_port** list, int noproto_is_err,
                                          (unsigned)cfg_uid, (unsigned)cfg_gid,
                                          ip, strerror(errno));
                        }
-                       chmod(ip, (mode_t)(S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP));
 #else
                        (void)cfg;
 #endif
@@ -813,7 +813,7 @@ print_mem(RES* ssl, struct worker* worker, struct daemon* daemon,
        iter = mod_get_mem(&worker->env, "iterator");
        respip = mod_get_mem(&worker->env, "respip");
 #ifdef CLIENT_SUBNET
-       subnet = mod_get_mem(&worker->env, "subnet");
+       subnet = mod_get_mem(&worker->env, "subnetcache");
 #endif /* CLIENT_SUBNET */
 #ifdef USE_IPSECMOD
        ipsecmod = mod_get_mem(&worker->env, "ipsecmod");
@@ -2015,7 +2015,7 @@ print_root_fwds(RES* ssl, struct iter_forwards* fwds, uint8_t* root)
 
 /** parse args into delegpt */
 static struct delegpt*
-parse_delegpt(RES* ssl, char* args, uint8_t* nm, int allow_names)
+parse_delegpt(RES* ssl, char* args, uint8_t* nm)
 {
        /* parse args and add in */
        char* p = args;
@@ -2037,40 +2037,35 @@ parse_delegpt(RES* ssl, char* args, uint8_t* nm, int allow_names)
                }
                /* parse address */
                if(!authextstrtoaddr(todo, &addr, &addrlen, &auth_name)) {
-                       if(allow_names) {
-                               uint8_t* n = NULL;
-                               size_t ln;
-                               int lb;
-                               if(!parse_arg_name(ssl, todo, &n, &ln, &lb)) {
-                                       (void)ssl_printf(ssl, "error cannot "
-                                               "parse IP address or name "
-                                               "'%s'\n", todo);
-                                       delegpt_free_mlc(dp);
-                                       return NULL;
-                               }
-                               if(!delegpt_add_ns_mlc(dp, n, 0)) {
-                                       (void)ssl_printf(ssl, "error out of memory\n");
-                                       free(n);
-                                       delegpt_free_mlc(dp);
-                                       return NULL;
-                               }
-                               free(n);
-
-                       } else {
+                       uint8_t* dname= NULL;
+                       int port;
+                       dname = authextstrtodname(todo, &port, &auth_name);
+                       if(!dname) {
                                (void)ssl_printf(ssl, "error cannot parse"
-                                       " IP address '%s'\n", todo);
+                                       " '%s'\n", todo);
+                               delegpt_free_mlc(dp);
+                               return NULL;
+                       }
+#if ! defined(HAVE_SSL_SET1_HOST) && ! defined(HAVE_X509_VERIFY_PARAM_SET1_HOST)
+                       if(auth_name)
+                               log_err("no name verification functionality in "
+                               "ssl library, ignored name for %s", todo);
+#endif
+                       if(!delegpt_add_ns_mlc(dp, dname, 0, auth_name, port)) {
+                               (void)ssl_printf(ssl, "error out of memory\n");
+                               free(dname);
                                delegpt_free_mlc(dp);
                                return NULL;
                        }
                } else {
 #if ! defined(HAVE_SSL_SET1_HOST) && ! defined(HAVE_X509_VERIFY_PARAM_SET1_HOST)
                        if(auth_name)
-                         log_err("no name verification functionality in "
+                               log_err("no name verification functionality in "
                                "ssl library, ignored name for %s", todo);
 #endif
                        /* add address */
                        if(!delegpt_add_addr_mlc(dp, &addr, addrlen, 0, 0,
-                               auth_name)) {
+                               auth_name, -1)) {
                                (void)ssl_printf(ssl, "error out of memory\n");
                                delegpt_free_mlc(dp);
                                return NULL;
@@ -2103,7 +2098,7 @@ do_forward(RES* ssl, struct worker* worker, char* args)
                forwards_delete_zone(fwd, LDNS_RR_CLASS_IN, root);
        } else {
                struct delegpt* dp;
-               if(!(dp = parse_delegpt(ssl, args, root, 0)))
+               if(!(dp = parse_delegpt(ssl, args, root)))
                        return;
                if(!forwards_add_zone(fwd, LDNS_RR_CLASS_IN, dp)) {
                        (void)ssl_printf(ssl, "error out of memory\n");
@@ -2149,7 +2144,7 @@ parse_fs_args(RES* ssl, char* args, uint8_t** nm, struct delegpt** dp,
 
        /* parse dp */
        if(dp) {
-               if(!(*dp = parse_delegpt(ssl, args, *nm, 1))) {
+               if(!(*dp = parse_delegpt(ssl, args, *nm))) {
                        free(*nm);
                        return 0;
                }
@@ -2865,6 +2860,8 @@ struct ratelimit_list_arg {
        int all;
        /** current time */
        time_t now;
+       /** if backoff is enabled */
+       int backoff;
 };
 
 #define ip_ratelimit_list_arg ratelimit_list_arg
@@ -2878,7 +2875,7 @@ rate_list(struct lruhash_entry* e, void* arg)
        struct rate_data* d = (struct rate_data*)e->data;
        char buf[257];
        int lim = infra_find_ratelimit(a->infra, k->name, k->namelen);
-       int max = infra_rate_max(d, a->now);
+       int max = infra_rate_max(d, a->now, a->backoff);
        if(a->all == 0) {
                if(max < lim)
                        return;
@@ -2896,7 +2893,7 @@ ip_rate_list(struct lruhash_entry* e, void* arg)
        struct ip_rate_key* k = (struct ip_rate_key*)e->key;
        struct ip_rate_data* d = (struct ip_rate_data*)e->data;
        int lim = infra_ip_ratelimit;
-       int max = infra_rate_max(d, a->now);
+       int max = infra_rate_max(d, a->now, a->backoff);
        if(a->all == 0) {
                if(max < lim)
                        return;
@@ -2914,6 +2911,7 @@ do_ratelimit_list(RES* ssl, struct worker* worker, char* arg)
        a.infra = worker->env.infra_cache;
        a.now = *worker->env.now;
        a.ssl = ssl;
+       a.backoff = worker->env.cfg->ratelimit_backoff;
        arg = skipwhite(arg);
        if(strcmp(arg, "+a") == 0)
                a.all = 1;
@@ -2932,6 +2930,7 @@ do_ip_ratelimit_list(RES* ssl, struct worker* worker, char* arg)
        a.infra = worker->env.infra_cache;
        a.now = *worker->env.now;
        a.ssl = ssl;
+       a.backoff = worker->env.cfg->ip_ratelimit_backoff;
        arg = skipwhite(arg);
        if(strcmp(arg, "+a") == 0)
                a.all = 1;
index 8720a52..d08f18d 100644 (file)
@@ -137,7 +137,7 @@ static void
 set_subnet_stats(struct worker* worker, struct ub_server_stats* svr,
        int reset)
 {
-       int m = modstack_find(&worker->env.mesh->mods, "subnet");
+       int m = modstack_find(&worker->env.mesh->mods, "subnetcache");
        struct subnet_env* sne;
        if(m == -1)
                return;
index 934a96c..457a080 100644 (file)
@@ -781,6 +781,7 @@ main(int argc, char* argv[])
        int cmdline_cfg = 0;
 #endif
 
+       checklock_start();
        log_init(NULL, 0, NULL);
        log_ident_default = strrchr(argv[0],'/')?strrchr(argv[0],'/')+1:argv[0];
        log_ident_set_default(log_ident_default);
index e9e163a..862affb 100644 (file)
@@ -146,7 +146,7 @@ worker_mem_report(struct worker* ATTR_UNUSED(worker),
                                (&worker->env, i);
 #ifdef CLIENT_SUBNET
                else if(strcmp(worker->env.mesh->mods.mod[i]->name,
-                       "subnet")==0)
+                       "subnetcache")==0)
                        subnet += (*worker->env.mesh->mods.mod[i]->get_mem)
                                (&worker->env, i);
 #endif /* CLIENT_SUBNET */
@@ -205,7 +205,7 @@ worker_mem_report(struct worker* ATTR_UNUSED(worker),
                                (&worker->env, i);
 #ifdef CLIENT_SUBNET
                else if(strcmp(worker->env.mesh->mods.mod[i]->name,
-                       "subnet")==0)
+                       "subnetcache")==0)
                        subnet += (*worker->env.mesh->mods.mod[i]->get_mem)
                                (&worker->env, i);
 #endif /* CLIENT_SUBNET */
@@ -449,7 +449,6 @@ answer_norec_from_cache(struct worker* worker, struct query_info* qinfo,
         * Then check if it needs validation, if so, this routine fails,
         * so that iterator can prime and validator can verify rrsets.
         */
-       struct edns_data edns_bak;
        uint16_t udpsize = edns->udp_size;
        int secure = 0;
        time_t timenow = *worker->env.now;
@@ -508,7 +507,6 @@ answer_norec_from_cache(struct worker* worker, struct query_info* qinfo,
                }
        }
        /* return this delegation from the cache */
-       edns_bak = *edns;
        edns->edns_version = EDNS_ADVERTISED_VERSION;
        edns->udp_size = EDNS_ADVERTISED_SIZE;
        edns->ext_rcode = 0;
@@ -518,15 +516,13 @@ answer_norec_from_cache(struct worker* worker, struct query_info* qinfo,
                worker->env.now_tv))
                        return 0;
        msg->rep->flags |= BIT_QR|BIT_RA;
-       if(!apply_edns_options(edns, &edns_bak, worker->env.cfg,
-               repinfo->c, worker->scratchpad) ||
-               !reply_info_answer_encode(&msg->qinfo, msg->rep, id, flags, 
+       if(!reply_info_answer_encode(&msg->qinfo, msg->rep, id, flags,
                repinfo->c->buffer, 0, 1, worker->scratchpad,
                udpsize, edns, (int)(edns->bits & EDNS_DO), secure)) {
                if(!inplace_cb_reply_servfail_call(&worker->env, qinfo, NULL, NULL,
                        LDNS_RCODE_SERVFAIL, edns, repinfo, worker->scratchpad,
                        worker->env.now_tv))
-                               edns->opt_list = NULL;
+                               edns->opt_list_inplace_cb_out = NULL;
                error_encode(repinfo->c->buffer, LDNS_RCODE_SERVFAIL, 
                        &msg->qinfo, id, flags, edns);
        }
@@ -604,7 +600,6 @@ answer_from_cache(struct worker* worker, struct query_info* qinfo,
        struct reply_info* rep, uint16_t id, uint16_t flags,
        struct comm_reply* repinfo, struct edns_data* edns)
 {
-       struct edns_data edns_bak;
        time_t timenow = *worker->env.now;
        uint16_t udpsize = edns->udp_size;
        struct reply_info* encode_rep = rep;
@@ -685,7 +680,6 @@ answer_from_cache(struct worker* worker, struct query_info* qinfo,
                }
        } else *is_secure_answer = 0;
 
-       edns_bak = *edns;
        edns->edns_version = EDNS_ADVERTISED_VERSION;
        edns->udp_size = EDNS_ADVERTISED_SIZE;
        edns->ext_rcode = 0;
@@ -722,15 +716,13 @@ answer_from_cache(struct worker* worker, struct query_info* qinfo,
                        if(!*partial_repp)
                                goto bail_out;
                }
-       } else if(!apply_edns_options(edns, &edns_bak, worker->env.cfg,
-               repinfo->c, worker->scratchpad) ||
-               !reply_info_answer_encode(qinfo, encode_rep, id, flags,
+       } else if(!reply_info_answer_encode(qinfo, encode_rep, id, flags,
                repinfo->c->buffer, timenow, 1, worker->scratchpad,
                udpsize, edns, (int)(edns->bits & EDNS_DO), *is_secure_answer)) {
                if(!inplace_cb_reply_servfail_call(&worker->env, qinfo, NULL, NULL,
                        LDNS_RCODE_SERVFAIL, edns, repinfo, worker->scratchpad,
                        worker->env.now_tv))
-                               edns->opt_list = NULL;
+                               edns->opt_list_inplace_cb_out = NULL;
                error_encode(repinfo->c->buffer, LDNS_RCODE_SERVFAIL, 
                        qinfo, id, flags, edns);
        }
@@ -789,6 +781,14 @@ chaos_replystr(sldns_buffer* pkt, char** str, int num, struct edns_data* edns,
        int i;
        unsigned int rd = LDNS_RD_WIRE(sldns_buffer_begin(pkt));
        unsigned int cd = LDNS_CD_WIRE(sldns_buffer_begin(pkt));
+       size_t udpsize = edns->udp_size;
+       edns->edns_version = EDNS_ADVERTISED_VERSION;
+       edns->udp_size = EDNS_ADVERTISED_SIZE;
+       edns->bits &= EDNS_DO;
+       if(!inplace_cb_reply_local_call(&worker->env, NULL, NULL, NULL,
+               LDNS_RCODE_NOERROR, edns, repinfo, worker->scratchpad,
+               worker->env.now_tv))
+                       edns->opt_list_inplace_cb_out = NULL;
        sldns_buffer_clear(pkt);
        sldns_buffer_skip(pkt, (ssize_t)sizeof(uint16_t)); /* skip id */
        sldns_buffer_write_u16(pkt, (uint16_t)(BIT_QR|BIT_RA));
@@ -804,6 +804,12 @@ chaos_replystr(sldns_buffer* pkt, char** str, int num, struct edns_data* edns,
        for(i=0; i<num; i++) {
                size_t len = strlen(str[i]);
                if(len>255) len=255; /* cap size of TXT record */
+               if(sldns_buffer_position(pkt)+2+2+2+4+2+1+len+
+                       calc_edns_field_size(edns) > udpsize) {
+                       sldns_buffer_write_u16_at(pkt, 6, i); /* ANCOUNT */
+                       LDNS_TC_SET(sldns_buffer_begin(pkt));
+                       break;
+               }
                sldns_buffer_write_u16(pkt, 0xc00c); /* compr ptr to query */
                sldns_buffer_write_u16(pkt, LDNS_RR_TYPE_TXT);
                sldns_buffer_write_u16(pkt, LDNS_RR_CLASS_CH);
@@ -813,13 +819,6 @@ chaos_replystr(sldns_buffer* pkt, char** str, int num, struct edns_data* edns,
                sldns_buffer_write(pkt, str[i], len);
        }
        sldns_buffer_flip(pkt);
-       edns->edns_version = EDNS_ADVERTISED_VERSION;
-       edns->udp_size = EDNS_ADVERTISED_SIZE;
-       edns->bits &= EDNS_DO;
-       if(!inplace_cb_reply_local_call(&worker->env, NULL, NULL, NULL,
-               LDNS_RCODE_NOERROR, edns, repinfo, worker->scratchpad,
-               worker->env.now_tv))
-                       edns->opt_list = NULL;
        if(sldns_buffer_capacity(pkt) >=
                sldns_buffer_limit(pkt)+calc_edns_field_size(edns))
                attach_edns_record(pkt, edns);
@@ -1004,7 +1003,6 @@ answer_notify(struct worker* w, struct query_info* qinfo,
        edns->udp_size = EDNS_ADVERTISED_SIZE;
        edns->ext_rcode = 0;
        edns->bits &= EDNS_DO;
-       edns->opt_list = NULL;
        error_encode(pkt, rcode, qinfo,
                *(uint16_t*)(void *)sldns_buffer_begin(pkt),
                sldns_buffer_read_u16_at(pkt, 2), edns);
@@ -1169,7 +1167,8 @@ worker_handle_request(struct comm_point* c, void* arg, int error,
 
        /* check if this query should be dropped based on source ip rate limiting */
        if(!infra_ip_ratelimit_inc(worker->env.infra_cache, repinfo,
-                       *worker->env.now, c->buffer)) {
+                       *worker->env.now,
+                       worker->env.cfg->ip_ratelimit_backoff, c->buffer)) {
                /* See if we are passed through with slip factor */
                if(worker->env.cfg->ip_ratelimit_factor != 0 &&
                        ub_random_max(worker->env.rnd,
@@ -1241,7 +1240,8 @@ worker_handle_request(struct comm_point* c, void* arg, int error,
                }
                goto send_reply;
        }
-       if((ret=parse_edns_from_pkt(c->buffer, &edns, worker->scratchpad)) != 0) {
+       if((ret=parse_edns_from_query_pkt(c->buffer, &edns, worker->env.cfg, c,
+                                       worker->scratchpad)) != 0) {
                struct edns_data reply_edns;
                verbose(VERB_ALGO, "worker parse edns: formerror.");
                log_addr(VERB_CLIENT,"from",&repinfo->addr, repinfo->addrlen);
@@ -1256,13 +1256,14 @@ worker_handle_request(struct comm_point* c, void* arg, int error,
                goto send_reply;
        }
        if(edns.edns_present) {
-               struct edns_option* edns_opt;
                if(edns.edns_version != 0) {
                        edns.ext_rcode = (uint8_t)(EDNS_RCODE_BADVERS>>4);
                        edns.edns_version = EDNS_ADVERTISED_VERSION;
                        edns.udp_size = EDNS_ADVERTISED_SIZE;
                        edns.bits &= EDNS_DO;
-                       edns.opt_list = NULL;
+                       edns.opt_list_in = NULL;
+                       edns.opt_list_out = NULL;
+                       edns.opt_list_inplace_cb_out = NULL;
                        edns.padding_block_size = 0;
                        verbose(VERB_ALGO, "query with bad edns version.");
                        log_addr(VERB_CLIENT,"from",&repinfo->addr, repinfo->addrlen);
@@ -1282,26 +1283,6 @@ worker_handle_request(struct comm_point* c, void* arg, int error,
                        log_addr(VERB_CLIENT,"from",&repinfo->addr, repinfo->addrlen);
                        edns.udp_size = NORMAL_UDP_SIZE;
                }
-               if(c->type != comm_udp) {
-                       edns_opt = edns_opt_list_find(edns.opt_list, LDNS_EDNS_KEEPALIVE);
-                       if(edns_opt && edns_opt->opt_len > 0) {
-                               edns.ext_rcode = 0;
-                               edns.edns_version = EDNS_ADVERTISED_VERSION;
-                               edns.udp_size = EDNS_ADVERTISED_SIZE;
-                               edns.bits &= EDNS_DO;
-                               edns.opt_list = NULL;
-                               verbose(VERB_ALGO, "query with bad edns keepalive.");
-                               log_addr(VERB_CLIENT,"from",&repinfo->addr, repinfo->addrlen);
-                               error_encode(c->buffer, LDNS_RCODE_FORMERR, &qinfo,
-                                       *(uint16_t*)(void *)sldns_buffer_begin(c->buffer),
-                                       sldns_buffer_read_u16_at(c->buffer, 2), NULL);
-                               if(sldns_buffer_capacity(c->buffer) >=
-                                  sldns_buffer_limit(c->buffer)+calc_edns_field_size(&edns))
-                                       attach_edns_record(c->buffer, &edns);
-                               regional_free_all(worker->scratchpad);
-                               goto send_reply;
-                       }
-               }
        }
        if(edns.udp_size > worker->daemon->cfg->max_udp_size &&
                c->type == comm_udp) {
@@ -1355,7 +1336,7 @@ worker_handle_request(struct comm_point* c, void* arg, int error,
                goto send_reply;
        }
        if(worker->env.auth_zones &&
-               rpz_apply_qname_trigger(worker->env.auth_zones,
+               rpz_callback_from_worker_request(worker->env.auth_zones,
                &worker->env, &qinfo, &edns, c->buffer, worker->scratchpad,
                repinfo, acladdr->taglist, acladdr->taglen, &worker->stats)) {
                regional_free_all(worker->scratchpad);
@@ -1453,7 +1434,7 @@ lookup_cache:
         * this is a two-pass operation, and lookup_qinfo is different for
         * each pass.  We should still pass the original qinfo to
         * answer_from_cache(), however, since it's used to build the reply. */
-       if(!edns_bypass_cache_stage(edns.opt_list, &worker->env)) {
+       if(!edns_bypass_cache_stage(edns.opt_list_in, &worker->env)) {
                is_expired_answer = 0;
                is_secure_answer = 0;
                h = query_info_hash(lookup_qinfo, sldns_buffer_read_u16_at(c->buffer, 2));
@@ -1987,9 +1968,10 @@ worker_delete(struct worker* worker)
 
 struct outbound_entry*
 worker_send_query(struct query_info* qinfo, uint16_t flags, int dnssec,
-       int want_dnssec, int nocaps, struct sockaddr_storage* addr,
-       socklen_t addrlen, uint8_t* zone, size_t zonelen, int ssl_upstream,
-       char* tls_auth_name, struct module_qstate* q)
+       int want_dnssec, int nocaps, int check_ratelimit,
+       struct sockaddr_storage* addr, socklen_t addrlen, uint8_t* zone,
+       size_t zonelen, int tcp_upstream, int ssl_upstream, char* tls_auth_name,
+       struct module_qstate* q, int* was_ratelimited)
 {
        struct worker* worker = q->env->worker;
        struct outbound_entry* e = (struct outbound_entry*)regional_alloc(
@@ -1998,9 +1980,10 @@ worker_send_query(struct query_info* qinfo, uint16_t flags, int dnssec,
                return NULL;
        e->qstate = q;
        e->qsent = outnet_serviced_query(worker->back, qinfo, flags, dnssec,
-               want_dnssec, nocaps, q->env->cfg->tcp_upstream,
+               want_dnssec, nocaps, check_ratelimit, tcp_upstream,
                ssl_upstream, tls_auth_name, addr, addrlen, zone, zonelen, q,
-               worker_handle_service_reply, e, worker->back->udp_buff, q->env);
+               worker_handle_service_reply, e, worker->back->udp_buff, q->env,
+               was_ratelimited);
        if(!e->qsent) {
                return NULL;
        }
@@ -2044,10 +2027,11 @@ struct outbound_entry* libworker_send_query(
        struct query_info* ATTR_UNUSED(qinfo),
        uint16_t ATTR_UNUSED(flags), int ATTR_UNUSED(dnssec),
        int ATTR_UNUSED(want_dnssec), int ATTR_UNUSED(nocaps),
+       int ATTR_UNUSED(check_ratelimit),
        struct sockaddr_storage* ATTR_UNUSED(addr), socklen_t ATTR_UNUSED(addrlen),
-       uint8_t* ATTR_UNUSED(zone), size_t ATTR_UNUSED(zonelen),
+       uint8_t* ATTR_UNUSED(zone), size_t ATTR_UNUSED(zonelen), int ATTR_UNUSED(tcp_upstream),
        int ATTR_UNUSED(ssl_upstream), char* ATTR_UNUSED(tls_auth_name),
-       struct module_qstate* ATTR_UNUSED(q))
+       struct module_qstate* ATTR_UNUSED(q), int* ATTR_UNUSED(was_ratelimited))
 {
        log_assert(0);
        return 0;
index c79bc9c..d01b436 100644 (file)
@@ -685,8 +685,12 @@ dns64_operate(struct module_qstate* qstate, enum module_ev event, int id,
        switch(event) {
                case module_event_new:
                        /* Tag this query as being new and fall through. */
-                       iq = (struct dns64_qstate*)regional_alloc(
-                               qstate->region, sizeof(*iq));
+                       if (!(iq = (struct dns64_qstate*)regional_alloc(
+                               qstate->region, sizeof(*iq)))) {
+                               log_err("out of memory");
+                               qstate->ext_state[id] = module_error;
+                               return;
+                       }
                        qstate->minfo[id] = iq;
                        iq->state = DNS64_NEW_QUERY;
                        iq->started_no_cache_store = qstate->no_cache_store;
@@ -913,8 +917,9 @@ dns64_adjust_ptr(struct module_qstate* qstate, struct module_qstate* super)
                     sizeof(struct dns_msg))))
         return;
     super->return_msg->qinfo = super->qinfo;
-    super->return_msg->rep = reply_info_copy(qstate->return_msg->rep, NULL,
-            super->region);
+    if (!(super->return_msg->rep = reply_info_copy(qstate->return_msg->rep,
+                    NULL, super->region)))
+        return;
 
     /*
      * Adjust the domain name of the answer RR set so that it matches the
index 9b324ae..4902447 100644 (file)
@@ -435,7 +435,7 @@ dnscrypt_hrtime(void)
 
 /**
  * Add the server nonce part to once.
- * The nonce is made half of client nonce and the seconf half of the server
+ * The nonce is made half of client nonce and the second half of the server
  * nonce, both of them of size crypto_box_HALF_NONCEBYTES.
  * \param[in] nonce: a uint8_t* of size crypto_box_NONCEBYTES
  */
@@ -674,7 +674,7 @@ dnsc_find_cert(struct dnsc_env* dnscenv, struct sldns_buffer* buffer)
 /**
  * Insert local-zone and local-data into configuration.
  * In order to be able to serve certs over TXT, we can reuse the local-zone and
- * local-data config option. The zone and qname are infered from the
+ * local-data config option. The zone and qname are inferred from the
  * provider_name and the content of the TXT record from the certificate content.
  * returns the number of certificate TXT record that were loaded.
  * < 0 in case of error.
index 666f54e..b0da9b7 100644 (file)
@@ -114,7 +114,7 @@ void dnsc_delete(struct dnsc_env *env);
 
 /**
  * handle a crypted dnscrypt request.
- * Determine wether or not a query is coming over the dnscrypt listener and
+ * Determine whether or not a query is coming over the dnscrypt listener and
  * attempt to uncurve it or detect if it is a certificate query.
  * return 0 in case of failure.
  */
@@ -122,7 +122,7 @@ int dnsc_handle_curved_request(struct dnsc_env* dnscenv,
                                struct comm_reply* repinfo);
 /**
  * handle an unencrypted dnscrypt request.
- * Determine wether or not a query is going over the dnscrypt channel and
+ * Determine whether or not a query is going over the dnscrypt channel and
  * attempt to curve it unless it was not crypted like when  it is a
  * certificate query.
  * \return 0 in case of failure.
index 91abd0d..8af7d3f 100644 (file)
@@ -1,3 +1,300 @@
+3 February 2022: Wouter
+       - Fix for #611: Integer overflow in sldns_wire2str_pkt_scan.
+
+2 February 2022: George
+       - Merge PR #532 from Shchelk: Fix: buffer overflow bug.
+       - Merge PR #616: Update ratelimit logic. It also introduces
+         ratelimit-backoff and ip-ratelimit-backoff configuration options.
+       - Change aggressive-nsec default to yes.
+       - Merge PR #617: Update stub/forward-host notation to accept port and
+         tls-auth-name.
+       - Update stream_ssl.tdir test to also use the new forward-host
+         notation.
+
+2 February 2022: Wouter
+       - Update version number in repo to 1.15.0 for upcoming release,
+         since it changes the aggressive-nsec default and the ratelimit change.
+       - Fix header comment for doxygen for authextstrtoaddr.
+       - please clang analyzer for loop in test code.
+       - Fix docker splint test to use more portable uname.
+       - Update contrib/aaaa-filter-iterator.patch with diff for current
+         software version.
+
+1 February 2022: George
+       - Merge PR #603 from fobser: Use OpenSSL 1.1 API to access DSA and RSA
+         internals.
+
+31 January 2022: George
+       - Fix review comment for use-after-free when failing to send UDP out.
+
+31 January 2022: Wouter
+       - iana portlist update.
+
+29 January 2022: George
+       - Fix tls-* and ssl-* documented alternate syntax to also be available
+         through remote-control and unbound-checkconf.
+       - Better cleanup on failed DoT/DoH listening socket creation.
+
+26 January 2022: George
+       - Fix #599: [FR] RFC 9156 (obsoletes RFC 7816), by noting the new RFC
+         document.
+
+26 January 2022: Wouter
+       - Test for NSID in SERVFAIL response due to DNSSEC bogus.
+
+25 January 2022: George
+       - Fix #588: Unbound 1.13.2 crashes due to p->pc is NULL in
+         serviced_udp_callback.
+       - Merge PR #612: TCP race condition.
+
+25 January 2022: Wouter
+       - Fix #610: Undefine-shift in sldns_str2wire_hip_buf.
+
+19 January 2022: George
+       - For dnstap, do not wakeupnow right there. Instead zero the timer to
+         force the wakeup callback asap.
+
+14 January 2022: George
+       - Merge PR #605:
+         - Fix EDNS to upstream where the same option could be attached
+            more than once.
+         - Add a region to serviced_query for allocations.
+
+14 January 2022: Wouter
+       - Add rpz: for-downstream: yesno option, where the RPZ zone is
+         authoritatively answered for, so the RPZ zone contents can be
+         checked with DNS queries directed at the RPZ zone.
+       - For #602: Allow the module-config "subnetcache validator cachedb
+         iterator".
+
+11 January 2022: George
+       - Fix prematurely terminated TCP queries when a reply has the same ID.
+
+7 January 2022: Wouter
+       - Merge #600 from pemensik: Change file mode before changing file
+         owner.
+
+5 January 2022: Wouter
+       - Fix for #596: fix that rpz return message is returned and not just
+         the rcode from the iterator return path. This fixes signal unset RA
+         after a CNAME.
+       - Fix unit tests for rpz now that the AA flag returns successfully from
+         the iterator loop.
+       - Fix for #596: add unit test for nsdname trigger and signal unset RA.
+       - Fix for #596: add unit test for nsip trigger and signal unset RA.
+       - Fix #598: Fix unbound-checkconf fatal error: module conf
+         'respip dns64 validator iterator' is not known to work.
+       - Fix for #596: Fix rpz-signal-nxdomain-ra to work for clientip
+         triggered operation.
+
+4 January 2022: Wouter
+       - Fix #596: unset the RA bit when a query is blocked by an unbound
+         RPZ nxdomain reply. The option rpz-signal-nxdomain-ra allows to
+         signal that a domain is externally blocked to clients when it
+         is blocked with NXDOMAIN by unsetting RA.
+       - Fix to add test for rpz-signal-nxdomain-ra.
+       - Fix #596: only unset RA when NXDOMAIN is signalled.
+       - Fix that RPZ does not set RD flag on replies, it should be copied
+         from the query.
+
+22 December 2021: George
+       - contrib/aaaa-filter-iterator.patch file renewed diff content to
+         apply cleanly to the current coderepo for the current code version.
+
+20 December 2021: George
+       - Fix #591: Unbound-anchor manpage links to non-existent license file.
+
+13 December 2021: George
+       - Add missing configure flags for optional features in the
+         documentation.
+       - Fix Unbound capitalization in the documentation.
+
+13 December 2021: Wouter
+       - Fix to pick up other class local zone information before unlock.
+
+10 December 2021: George
+       - Allow local-data for classes other than IN to inherit a configured
+         local-zone's type if possible, instead of defaulting to type
+         transparent as per the implicit rule.
+
+10 December 2021: Wouter
+       - Add code similar to fix for ldns for tab between strings, for
+         consistency, the test case was not broken.
+
+6 December 2021: Wouter
+       - Merge PR #581 from fobser: Fix -Wmissing-prototypes and -Wshadow
+         warnings in rpz.
+       - Fix validator debug output about DS support, print correct algorithm.
+
+3 December 2021: Wouter
+       - Fix compile warning for if_nametoindex on windows 64bit.
+
+1 December 2021: Wouter
+       - configure is set to 1.14.0, and release branch.
+         This was released as version 1.14.0 on 9 Dec 2021, with the doxygen
+         fix below included. The main branch continues as 1.14.1.
+       - Fix doc/unbound.doxygen to remove obsolete tag warning.
+
+1 December 2021: George
+       - Merge PR #511 from yan12125: Reduce unnecessary linking.
+       - Merge PR #493 from Jaap: Fix generation of libunbound.pc.
+       - Merge PR #555 from fobser: Allow interface names as scope-id in IPv6
+         link-local addresses.
+       - Merge PR #562 from Willem: Reset keepalive per new tcp session.
+       - Merge PR #522 from sibeream: memory management violations fixed.
+       - Merge PR #530 from Shchelk: Fix: dereferencing a null pointer.
+       - Fix #454: listen_dnsport.c:825: error: â€˜IPV6_TCLASS’ undeclared.
+       - Fix #574: Review fixes for size allocation.
+
+30 November 2021: Wouter
+       - Fix to remove git tracking and ci information from release tarballs.
+       - iana portlist update.
+
+29 November 2021: Wouter
+       - Merge PR #570 from rex4539: Fix typos.
+       - Fix for #570: regen aclocal.m4, fix configure.ac for spelling.
+       - Fix to make python module opt_list use opt_list_in.
+       - Fix #574: unbound-checkconf reports fatal error if interface names
+         are used as value for interfaces:
+       - Fix #574: Review fixes for it.
+       - Fix #576: [FR] UB_* error codes in unbound.h
+       - Fix #574: Review fix for spelling.
+
+15 November 2021: Tom
+       - Improve EDNS option handling, now also works for synthesised
+         responses such as local-data and server.id CH TXT responses.
+
+5 November 2021: George
+       - Fix for #558: fix loop in comm_point->tcp_free when a comm_point is
+         reclaimed more than once during callbacks.
+       - Fix for #558: clear the UB_EV_TIMEOUT bit before adding an event.
+
+5 November 2021: Wouter
+       - Fix that forward-zone name is documented as the full name of the
+         zone. It is not relative but a fully qualified domain name.
+       - Fix analyzer review failure in rpz action override code to not
+         crash on unlocking the local zone lock.
+       - Fix to remove unused code from rpz resolve client and action
+         function.
+       - Merge #565: unbound.service.in: Disable ProtectKernelTunables again.
+
+2 November 2021: Wouter
+       - Fix #552: Unbound assumes index.html exists on RPZ host.
+
+11 October 2021: Wouter
+       - Fix chaos replies to have truncation for short message lengths,
+         or long reply strings.
+       - Fix to protect custom regional create against small values.
+
+4 October 2021: Wouter
+       - Fix to add example.conf note for outbound-msg-retry.
+
+27 September 2021: Wouter
+       - Implement RFC8375: Special-Use Domain 'home.arpa.'.
+
+21 September 2021: Wouter
+       - For crosscompile on windows, detect 64bit stackprotector library.
+       - Fix crosscompile shell syntax.
+       - Fix crosscompile windows to use libssp when it exists.
+       - For the windows compile script disable gost.
+       - Fix that on windows, use BIO_set_callback_ex instead of deprecated
+         BIO_set_callback.
+       - Fix crosscompile script for the shared build flags.
+
+20 September 2021: Wouter
+       - Fix crosscompile on windows to work with openssl 3.0.0 the
+         link with ws2_32 needs -l:libssp.a for __strcpy_chk.
+         Also copy results from lib64 directory if needed.
+
+10 September 2021: Wouter
+       - Fix initialisation errors reported by gcc sanitizer.
+       - Fix lock debug code for gcc sanitizer reports.
+       - Fix more initialisation errors reported by gcc sanitizer.
+
+8 September 2021: Wouter
+       - Merged #41 from Moritz Schneider: made outbound-msg-retry
+         configurable.
+       - Small fixes for #41: changelog, conflicts resolved,
+         processQueryResponse takes an iterator env argument like other
+         functions in the iterator, no colon in string for set_option,
+         and some whitespace style, to make it similar to the rest.
+       - Fix for #41: change outbound retry to int to fix signed comparison
+         warnings.
+       - Fix root_anchor test to check with new icannbundle date.
+
+3 September 2021: Wouter
+       - Fix #538: Fix subnetcache statistics.
+
+1 September 2021: Wouter
+       - Fix tcp fastopen failure when disabled, try normal connect instead.
+
+27 August 2021: Wouter
+       - Fix #533: Negative responses get cached even when setting
+         cache-max-negative-ttl: 1
+
+25 August 2021: Wouter
+       - Merge #401: RPZ triggers. This add additional RPZ triggers,
+         unbound supports a full set of rpz triggers, and this now
+         includes nsdname, nsip and clientip triggers. Also actions
+         are fully supported, and this now includes the tcp-only action.
+       - Fix #536: error: RPZ: name of record (drop.spamhaus.org.rpz.local.)
+         to insert into RPZ.
+       - Fix the stream wait stream_wait_count_lock and http2 buffer locks
+         setup and desetup from race condition.
+       - Fix RPZ locks. Do not unlock zones lock if requested and rpz find
+         zone does not find the zone. Readlock the clientip that is found
+         for ipbased triggers. Unlock the nsdname zone lock when done.
+         Unlock zone and ip in rpz nsip and nsdname callback. Unlock
+         authzone and localzone if clientip found in rpz worker call.
+       - Fix compile warning in libunbound for listen desetup routine.
+       - Fix asynclook unit test for setup of lockchecks before log.
+
+20 August 2021: Wouter
+       - Fix #529: Fix: log_assert does nothing if UNBOUND_DEBUG is
+         undefined.
+       - Fix #531: Fix: passed to proc after free.
+
+17 August 2021: Wouter
+       - Fix that --with-ssl can use "/usr/include/openssl11" to pass the
+         location of a different openssl version.
+       - Fix #527: not sending quad9 cert to syslog (and may be more).
+       - Fix sed script in ssldir split handling.
+
+16 August 2021: George
+       - Merge PR #528 from fobser: Make sldns_str2wire_svcparam_buf()
+         static.
+
+16 August 2021: Wouter
+       - Fix to support harden-algo-downgrade for ZONEMD dnssec checks.
+
+13 August 2021: Wouter
+       - Support using system-wide crypto policies.
+       - Fix for #431: Squelch permission denied errors for udp connect,
+         and udp send, they are visible at higher verbosity settings.
+       - Fix zonemd verification of key that is not in DNS but in the zone
+         and needs a chain of trust.
+       - zonemd, fix order of bogus printout string manipulation.
+
+12 August 2021: George
+       - Merge PR #514, from ziollek: Docker environment for run tests.
+       - For #514: generate configure.
+
+12 August 2021: Wouter
+       - And 1.13.2rc1 became the 1.13.2 with the fix for the python module
+         build. The current code repository continues with version 1.13.3.
+       - Add test tool readzone to .gitignore.
+       - Merge #521: Update mini_event.c.
+       - Merge #523: fix: free() call more than once with the same pointer.
+       - Merge #519: Support for selective enabling tcp-upstream for
+         stub/forward zones.
+       - For #519: note stub-tcp-upstream and forward-tcp-upstream in
+         the example configuration file.
+       - For #519: yacc and lex. And fix python bindings, and test program
+         unbound-dnstap-socket.
+       - For #519: fix comments for doxygen.
+       - Fix to print error from unbound-anchor for writing to the key
+         file, also when not verbose.
+
 5 August 2021: Wouter
        - Tag for 1.13.2rc1 release.
        - Fix #520: Unbound 1.13.2rc1 fails to build python module.
index a051380..9d9794d 100644 (file)
@@ -1,4 +1,4 @@
-README for Unbound 1.13.2
+README for Unbound 1.15.0
 Copyright 2007 NLnet Labs
 http://unbound.net
 
index 1ba5184..ac2de59 100644 (file)
@@ -1,7 +1,7 @@
 #
 # Example configuration file.
 #
-# See unbound.conf(5) man page, version 1.13.2.
+# See unbound.conf(5) man page, version 1.15.0.
 #
 # this is a comment.
 
@@ -82,13 +82,13 @@ server:
        # num-queries-per-thread, or, use as many as the OS will allow you.
        # outgoing-range: 4096
 
-       # permit unbound to use this port number or port range for
+       # permit Unbound to use this port number or port range for
        # making outgoing queries, using an outgoing interface.
        # outgoing-port-permit: 32768
 
-       # deny unbound the use this of port number or port range for
+       # deny Unbound the use this of port number or port range for
        # making outgoing queries, using an outgoing interface.
-       # Use this to make sure unbound does not grab a UDP port that some
+       # Use this to make sure Unbound does not grab a UDP port that some
        # other server on this computer needs. The default is to avoid
        # IANA-assigned port numbers.
        # If multiple outgoing-port-permit and outgoing-port-avoid options
@@ -164,6 +164,9 @@ server:
        # perform connect for UDP sockets to mitigate ICMP side channel.
        # udp-connect: yes
 
+       # The number of retries when a non-positive response is received.
+       # outbound-msg-retry: 5
+
        # 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
@@ -251,7 +254,7 @@ server:
        # use-systemd: no
 
        # Detach from the terminal, run in background, "yes" or "no".
-       # Set the value to "no" when unbound runs as systemd service.
+       # Set the value to "no" when Unbound runs as systemd service.
        # do-daemonize: yes
 
        # control which clients are allowed to make (recursive) queries
@@ -304,7 +307,7 @@ server:
        # The pid file can be absolute and outside of the chroot, it is
        # written just prior to performing the chroot and dropping permissions.
        #
-       # Additionally, unbound may need to access /dev/urandom (for entropy).
+       # Additionally, Unbound may need to access /dev/urandom (for entropy).
        # How to do this is specific to your OS.
        #
        # If you give "" no chroot is performed. The path must not end in a /.
@@ -439,7 +442,7 @@ server:
 
        # Aggressive NSEC uses the DNSSEC NSEC chain to synthesize NXDOMAIN
        # and other denials, using information from previous NXDOMAINs answers.
-       # aggressive-nsec: no
+       # aggressive-nsec: yes
 
        # Use 0x20-encoded random bits in the query to foil spoof attempts.
        # This feature is an experimental implementation of draft dns-0x20.
@@ -514,7 +517,7 @@ server:
        # Use several entries, one per domain name, to track multiple zones.
        #
        # If you want to perform DNSSEC validation, run unbound-anchor before
-       # you start unbound (i.e. in the system boot scripts).
+       # you start Unbound (i.e. in the system boot scripts).
        # And then enable the auto-trust-anchor-file config item.
        # Please note usage of unbound-anchor root anchor is at your own risk
        # and under the terms of our LICENSE (see that file in the source).
@@ -582,7 +585,7 @@ server:
        # val-permissive-mode: no
 
        # Ignore the CD flag in incoming queries and refuse them bogus data.
-       # Enable it if the only clients of unbound are legacy servers (w2008)
+       # Enable it if the only clients of Unbound are legacy servers (w2008)
        # that set CD but cannot validate themselves.
        # ignore-cd-flag: no
 
@@ -612,7 +615,7 @@ server:
 
        # Return the original TTL as received from the upstream name server rather
        # than the decrementing TTL as stored in the cache.  Enabling this feature
-       # does not impact cache expiry, it only changes the TTL unbound embeds in
+       # does not impact cache expiry, it only changes the TTL Unbound embeds in
        # responses to queries. Note that enabling this feature implicitly disables
        # enforcement of the configured minimum and maximum TTL.
        # serve-original-ttl: no
@@ -666,6 +669,7 @@ server:
        # local-zone: "localhost." nodefault
        # local-zone: "127.in-addr.arpa." nodefault
        # local-zone: "1.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.ip6.arpa." nodefault
+       # local-zone: "home.arpa." nodefault
        # local-zone: "onion." nodefault
        # local-zone: "test." nodefault
        # local-zone: "invalid." nodefault
@@ -705,9 +709,9 @@ server:
        # Add example.com into ipset
        # local-zone: "example.com" ipset
 
-       # If unbound is running service for the local host then it is useful
+       # If Unbound is running service for the local host then it is useful
        # to perform lan-wide lookups to the upstream, and unblock the
-       # long list of local-zones above.  If this unbound is a dns server
+       # long list of local-zones above.  If this Unbound is a dns server
        # for a network of computers, disabled is better and stops information
        # leakage of local lan information.
        # unblock-lan-zones: no
@@ -856,6 +860,10 @@ server:
        # 0 blocks when ratelimited, otherwise let 1/xth traffic through
        # ratelimit-factor: 10
 
+       # Aggressive rate limit when the limit is reached and until demand has
+       # decreased in a 2 second rate window.
+       # ratelimit-backoff: no
+
        # override the ratelimit for a specific domain name.
        # give this setting multiple times to have multiple overrides.
        # ratelimit-for-domain: example.com 1000
@@ -876,6 +884,10 @@ server:
        # 0 blocks when ip is ratelimited, otherwise let 1/xth traffic through
        # ip-ratelimit-factor: 10
 
+       # Aggressive rate limit when the limit is reached and until demand has
+       # decreased in a 2 second rate window.
+       # ip-ratelimit-backoff: no
+
        # Limit the number of connections simultaneous from a netblock
        # tcp-connection-limit: 192.0.2.0/24 12
 
@@ -885,7 +897,7 @@ server:
        # the number of servers that will be used in the fast server selection.
        # fast-server-num: 3
 
-       # Specific options for ipsecmod. unbound needs to be configured with
+       # Specific options for ipsecmod. Unbound needs to be configured with
        # --enable-ipsecmod for these to take effect.
        #
        # Enable or disable ipsecmod (it still needs to be defined in
@@ -897,7 +909,7 @@ server:
        # listed in module-config (above).
        # ipsecmod-hook: "./my_executable"
        #
-       # When enabled unbound will reply with SERVFAIL if the return value of
+       # When enabled Unbound will reply with SERVFAIL if the return value of
        # the ipsecmod-hook is not 0.
        # ipsecmod-strict: no
        #
@@ -962,10 +974,10 @@ remote-control:
        # For local sockets this option is ignored, and TLS is not used.
        # control-use-cert: "yes"
 
-       # unbound server key file.
+       # Unbound server key file.
        # server-key-file: "@UNBOUND_RUN_DIR@/unbound_server.key"
 
-       # unbound server certificate file.
+       # Unbound server certificate file.
        # server-cert-file: "@UNBOUND_RUN_DIR@/unbound_server.pem"
 
        # unbound-control key file.
@@ -987,6 +999,7 @@ remote-control:
 #      stub-addr: 192.0.2.68
 #      stub-prime: no
 #      stub-first: no
+#      stub-tcp-upstream: no
 #      stub-tls-upstream: no
 #      stub-no-cache: no
 # stub-zone:
@@ -1004,6 +1017,7 @@ remote-control:
 #      forward-addr: 192.0.2.68
 #      forward-addr: 192.0.2.73@5355  # forward to port 5355.
 #      forward-first: no
+#      forward-tcp-upstream: no
 #      forward-tls-upstream: no
 #      forward-no-cache: no
 # forward-zone:
@@ -1066,8 +1080,9 @@ remote-control:
 #      local-zone: "example.com" refuse
 
 # DNSCrypt
+# To enable, use --enable-dnscrypt to configure before compiling.
 # Caveats:
-# 1. the keys/certs cannot be produced by unbound. You can use dnscrypt-wrapper
+# 1. the keys/certs cannot be produced by Unbound. You can use dnscrypt-wrapper
 #   for this: https://github.com/cofyc/dnscrypt-wrapper/blob/master/README.md#usage
 # 2. dnscrypt channel attaches to an interface. you MUST set interfaces to
 #   listen on `dnscrypt-port` with the follo0wing snippet:
@@ -1086,7 +1101,9 @@ remote-control:
 #     dnscrypt-provider-cert: /path/unbound-conf/keys2/1.cert
 
 # CacheDB
-# Enable external backend DB as auxiliary cache.  Specify the backend name
+# External backend DB as auxiliary cache.
+# To enable, use --enable-cachedb to configure before compiling.
+# Specify the backend name
 # (default is "testframe", which has no use other than for debugging and
 # testing) and backend-specific options.  The 'cachedb' module must be
 # included in module-config, just before the iterator module.
@@ -1096,6 +1113,7 @@ remote-control:
 #     secret-seed: "default"
 #
 #     # For "redis" backend:
+#     # (to enable, use --with-libhiredis to configure before compiling)
 #     # redis server's IP address or host name
 #     redis-server-host: 127.0.0.1
 #     # redis server's TCP port
@@ -1107,7 +1125,9 @@ remote-control:
 
 # IPSet
 # Add specify domain into set via ipset.
-# Note: To enable ipset unbound needs to run as root user.
+# To enable:
+# o use --enable-ipset to configure before compiling;
+# o Unbound then needs to run as root user.
 # ipset:
 #     # set name for ip v4 addresses
 #     name-v4: "list-v4"
@@ -1115,9 +1135,10 @@ remote-control:
 #     name-v6: "list-v6"
 #
 
-# Dnstap logging support, if compiled in.  To enable, set the dnstap-enable
-# to yes and also some of dnstap-log-..-messages to yes.  And select an
-# upstream log destination, by socket path, TCP or TLS destination.
+# Dnstap logging support, if compiled in by using --enable-dnstap to configure.
+# To enable, set the dnstap-enable to yes and also some of
+# dnstap-log-..-messages to yes.  And select an upstream log destination, by
+# socket path, TCP or TLS destination.
 # dnstap:
 #      dnstap-enable: no
 #      # if set to yes frame streams will be used in bidirectional mode
@@ -1130,7 +1151,7 @@ remote-control:
 #      dnstap-tls: yes
 #      # name for authenticating the upstream server. or "" disabled.
 #      dnstap-tls-server-name: ""
-#      # if "", it uses the cert bundle from the main unbound config.
+#      # if "", it uses the cert bundle from the main Unbound config.
 #      dnstap-tls-cert-bundle: ""
 #      # key file for client authentication, or "" disabled.
 #      dnstap-tls-client-key-file: ""
@@ -1150,10 +1171,11 @@ remote-control:
 #      dnstap-log-forwarder-response-messages: no
 
 # Response Policy Zones
-# RPZ policies. Applied in order of configuration. QNAME and Response IP
-# Address trigger are the only supported triggers. Supported actions are:
-# NXDOMAIN, NODATA, PASSTHRU, DROP and Local Data. Policies can be loaded from
-# file, using zone transfer, or using HTTP. The respip module needs to be added
+# RPZ policies. Applied in order of configuration. QNAME, Response IP
+# Address, nsdname, nsip and clientip triggers are supported. Supported
+# actions are: NXDOMAIN, NODATA, PASSTHRU, DROP, Local Data, tcp-only
+# and drop.  Policies can be loaded from a file, or using zone
+# transfer, or using HTTP. The respip module needs to be added
 # to the module-config, e.g.: module-config: "respip validator iterator".
 # rpz:
 #     name: "rpz.example.com"
@@ -1165,4 +1187,6 @@ remote-control:
 #     rpz-cname-override: www.example.org
 #     rpz-log: yes
 #     rpz-log-name: "example policy"
+#     rpz-signal-nxdomain-ra: no
+#     for-downstream: no
 #     tags: "example"
index 73562cd..7df4f59 100644 (file)
@@ -1,4 +1,4 @@
-.TH "libunbound" "3" "Aug 12, 2021" "NLnet Labs" "unbound 1.13.2"
+.TH "libunbound" "3" "Feb 10, 2022" "NLnet Labs" "unbound 1.15.0"
 .\"
 .\" 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.13.2 functions.
+\- Unbound DNS validating resolver 1.15.0 functions.
 .SH "SYNOPSIS"
 .B #include <unbound.h>
 .LP
index 25f7f1b..268640d 100644 (file)
@@ -1,4 +1,4 @@
-.TH "unbound-anchor" "8" "Aug 12, 2021" "NLnet Labs" "unbound 1.13.2"
+.TH "unbound-anchor" "8" "Feb 10, 2022" "NLnet Labs" "unbound 1.15.0"
 .\"
 .\" unbound-anchor.8 -- unbound anchor maintenance utility manual
 .\"
@@ -41,7 +41,7 @@ update certificate files.
 .P
 It tests if the root anchor file works, and if not, and an update is possible,
 attempts to update the root anchor using the root update certificate.
-It performs a https fetch of root-anchors.xml and checks the results (RFC7958), 
+It performs a https fetch of root-anchors.xml and checks the results (RFC7958),
 if all checks are successful, it updates the root anchor file.  Otherwise
 the root anchor file is unchanged.  It performs RFC5011 tracking if the
 DNSSEC information available via the DNS makes that possible.
@@ -159,7 +159,7 @@ Or something more suitable for your operational environment.
 The root keys and update certificate included in this tool
 are provided for convenience and under the terms of our
 license (see the LICENSE file in the source distribution or
-http://unbound.nlnetlabs.nl/svn/trunk/LICENSE) and might be stale or
+https://github.com/NLnetLabs/unbound/blob/master/LICENSE) and might be stale or
 not suitable to your purpose.
 .P
 By running "unbound\-anchor \-l" the  keys and certificate that are
@@ -185,5 +185,5 @@ Source for the root key information.
 .I https://data.iana.org/root\-anchors/root\-anchors.p7s
 Signature on the root key information.
 .SH "SEE ALSO"
-\fIunbound.conf\fR(5), 
+\fIunbound.conf\fR(5),
 \fIunbound\fR(8).
index 3756201..ac8782d 100644 (file)
@@ -1,4 +1,4 @@
-.TH "unbound-checkconf" "8" "Aug 12, 2021" "NLnet Labs" "unbound 1.13.2"
+.TH "unbound-checkconf" "8" "Feb 10, 2022" "NLnet Labs" "unbound 1.15.0"
 .\"
 .\" unbound-checkconf.8 -- unbound configuration checker manual
 .\"
@@ -9,7 +9,7 @@
 .\"
 .SH "NAME"
 unbound\-checkconf
-\- Check unbound configuration file for errors.
+\- Check Unbound configuration file for errors.
 .SH "SYNOPSIS"
 .B unbound\-checkconf
 .RB [ \-h ]
@@ -21,8 +21,8 @@ unbound\-checkconf
 .B Unbound\-checkconf
 checks the configuration file for the
 \fIunbound\fR(8)
-DNS resolver for syntax and other errors. 
-The config file syntax is described in 
+DNS resolver for syntax and other errors.
+The config file syntax is described in
 \fIunbound.conf\fR(5).
 .P
 The available options are:
@@ -34,19 +34,19 @@ Show the version and commandline option help.
 Print full pathname, with chroot applied to it.  Use with the \-o option.
 .TP
 .B \-o\fI option
-If given, after checking the config file the value of this option is 
+If given, after checking the config file the value of this option is
 printed to stdout.  For "" (disabled) options an empty line is printed.
 .TP
 .I cfgfile
-The config file to read with settings for unbound. It is checked.
+The config file to read with settings for Unbound. It is checked.
 If omitted, the config file at the default location is checked.
 .SH "EXIT CODE"
-The unbound\-checkconf program exits with status code 1 on error, 
+The unbound\-checkconf program exits with status code 1 on error,
 0 for a correct config file.
 .SH "FILES"
 .TP
 .I @ub_conf_file@
-unbound configuration file.
+Unbound configuration file.
 .SH "SEE ALSO"
-\fIunbound.conf\fR(5), 
+\fIunbound.conf\fR(5),
 \fIunbound\fR(8).
index fb3510f..9d0c10e 100644 (file)
@@ -1,4 +1,4 @@
-.TH "unbound-control" "8" "Aug 12, 2021" "NLnet Labs" "unbound 1.13.2"
+.TH "unbound-control" "8" "Feb 10, 2022" "NLnet Labs" "unbound 1.15.0"
 .\"
 .\" unbound-control.8 -- unbound remote control manual
 .\"
 .SH "SYNOPSIS"
 .B unbound\-control
 .RB [ \-hq ]
-.RB [ \-c 
+.RB [ \-c
 .IR cfgfile ]
-.RB [ \-s 
+.RB [ \-s
 .IR server ]
 .IR command
 .SH "DESCRIPTION"
 .B Unbound\-control
 performs remote administration on the \fIunbound\fR(8) DNS server.
-It reads the configuration file, contacts the unbound server over SSL
+It reads the configuration file, contacts the Unbound server over SSL
 sends the command and displays the result.
 .P
 The available options are:
@@ -44,8 +44,8 @@ quiet, if the option is given it does not print anything if it works ok.
 There are several commands that the server understands.
 .TP
 .B start
-Start the server. Simply execs \fIunbound\fR(8).  The unbound executable 
-is searched for in the \fBPATH\fR set in the environment.  It is started 
+Start the server. Simply execs \fIunbound\fR(8).  The Unbound executable
+is searched for in the \fBPATH\fR set in the environment.  It is started
 with the config file specified using \fI\-c\fR or the default config file.
 .TP
 .B stop
@@ -65,8 +65,8 @@ daemon release the file it is logging to.  If you are using syslog it will
 attempt to close and open the syslog (which may not work if chrooted).
 .TP
 .B stats
-Print statistics. Resets the internal counters to zero, this can be 
-controlled using the \fBstatistics\-cumulative\fR config statement. 
+Print statistics. Resets the internal counters to zero, this can be
+controlled using the \fBstatistics\-cumulative\fR config statement.
 Statistics are printed with one [name]: [value] per line.
 .TP
 .B stats_noreset
@@ -74,7 +74,7 @@ Peek at statistics. Prints them like the \fBstats\fR command does, but does not
 reset the internal counters to zero.
 .TP
 .B status
-Display server status. Exit code 3 if not running (the connection to the 
+Display server status. Exit code 3 if not running (the connection to the
 port is refused), 1 on error, 0 if running.
 .TP
 .B local_zone \fIname\fR \fItype
@@ -88,14 +88,14 @@ it.  If the zone does not exist, the command succeeds.
 .B local_data \fIRR data...
 Add new local data, the given resource record. Like \fBlocal\-data\fR
 config statement, except for when no covering zone exists.  In that case
-this remote control command creates a transparent zone with the same 
+this remote control command creates a transparent zone with the same
 name as this record.
 .TP
 .B local_data_remove \fIname
 Remove all RR data from local name.  If the name already has no items,
 nothing happens.  Often results in NXDOMAIN for the name (in a static zone),
-but if the name has become an empty nonterminal (there is still data in 
-domain names below the removed name), NOERROR nodata answers are the 
+but if the name has become an empty nonterminal (there is still data in
+domain names below the removed name), NOERROR nodata answers are the
 result for that name.
 .TP
 .B local_zones
@@ -125,22 +125,22 @@ in old or wrong data returned to clients.  Loading data into the cache
 in this way is supported in order to aid with debugging.
 .TP
 .B lookup \fIname
-Print to stdout the name servers that would be used to look up the 
+Print to stdout the name servers that would be used to look up the
 name specified.
 .TP
 .B flush \fIname
 Remove the name from the cache. Removes the types
 A, AAAA, NS, SOA, CNAME, DNAME, MX, PTR, SRV and NAPTR.
-Because that is fast to do. Other record types can be removed using 
-.B flush_type 
-or 
+Because that is fast to do. Other record types can be removed using
+.B flush_type
+or
 .B flush_zone\fR.
 .TP
 .B flush_type \fIname\fR \fItype
 Remove the name, type information from the cache.
 .TP
 .B flush_zone \fIname
-Remove all information at or below the name from the cache. 
+Remove all information at or below the name from the cache.
 The rrsets and key entries are removed so that new lookups will be performed.
 This needs to walk and inspect the entire cache, and is a slow operation.
 The entries are set to expired in the implementation of this command (so,
@@ -187,7 +187,7 @@ therefore not flushed.  The option must end with a ':' and whitespace
 must be between the option and the value.  Some values may not have an
 effect if set this way, the new values are not written to the config file,
 not all options are supported.  This is different from the set_option call
-in libunbound, where all values work because unbound has not been initialized.
+in libunbound, where all values work because Unbound has not been initialized.
 .IP
 The values that work are: statistics\-interval, statistics\-cumulative,
 do\-not\-query\-localhost, harden\-short\-bufsize, harden\-large\-queries,
@@ -227,36 +227,36 @@ List the local data RRs in use.  The resource records are printed.
 .TP
 .B insecure_add \fIzone
 Add a \fBdomain\-insecure\fR for the given zone, like the statement in unbound.conf.
-Adds to the running unbound without affecting the cache contents (which may
+Adds to the running Unbound without affecting the cache contents (which may
 still be bogus, use \fBflush_zone\fR to remove it), does not affect the config file.
 .TP
 .B insecure_remove \fIzone
 Removes domain\-insecure for the given zone.
 .TP
 .B forward_add \fR[\fI+i\fR] \fIzone addr ...
-Add a new forward zone to running unbound.  With +i option also adds a
+Add a new forward zone to running Unbound.  With +i option also adds a
 \fIdomain\-insecure\fR for the zone (so it can resolve insecurely if you have
 a DNSSEC root trust anchor configured for other names).
 The addr can be IP4, IP6 or nameserver names, like \fIforward-zone\fR config
 in unbound.conf.
 .TP
 .B forward_remove \fR[\fI+i\fR] \fIzone
-Remove a forward zone from running unbound.  The +i also removes a
+Remove a forward zone from running Unbound.  The +i also removes a
 \fIdomain\-insecure\fR for the zone.
 .TP
 .B stub_add \fR[\fI+ip\fR] \fIzone addr ...
-Add a new stub zone to running unbound.  With +i option also adds a
+Add a new stub zone to running Unbound.  With +i option also adds a
 \fIdomain\-insecure\fR for the zone.  With +p the stub zone is set to prime,
 without it it is set to notprime.  The addr can be IP4, IP6 or nameserver
 names, like the \fIstub-zone\fR config in unbound.conf.
 .TP
 .B stub_remove \fR[\fI+i\fR] \fIzone
-Remove a stub zone from running unbound.  The +i also removes a
+Remove a stub zone from running Unbound.  The +i also removes a
 \fIdomain\-insecure\fR for the zone.
 .TP
 .B forward \fR[\fIoff\fR | \fIaddr ...\fR ]
 Setup forwarding mode.  Configures if the server should ask other upstream
-nameservers, should go to the internet root nameservers itself, or show 
+nameservers, should go to the internet root nameservers itself, or show
 the current config.  You could pass the nameservers after a DHCP update.
 .IP
 Without arguments the current list of addresses used to forward all queries
@@ -296,7 +296,7 @@ status, indicating if the zone is expired and current serial number.
 Reload the auth zone from zonefile.  The zonefile is read in overwriting
 the current contents of the zone in memory.  This changes the auth zone
 contents itself, not the cache contents.  Such cache contents exists if
-you set unbound to validate with for-upstream yes and that can be cleared
+you set Unbound to validate with for-upstream yes and that can be cleared
 with \fBflush_zone\fR \fIzone\fR.
 .TP
 .B auth_zone_transfer \fIzone\fR
@@ -336,7 +336,7 @@ Add a list of \fIlocal_data\fR for given view from stdin.  Like local_datas.
 .SH "EXIT CODE"
 The unbound\-control program exits with status code 1 on error, 0 on success.
 .SH "SET UP"
-The setup requires a self\-signed certificate and private keys for both 
+The setup requires a self\-signed certificate and private keys for both
 the server and client.  The script \fIunbound\-control\-setup\fR generates
 these in the default run directory, or with \-d in another directory.
 If you change the access control permissions on the key files you can decide
@@ -350,7 +350,7 @@ If you have not configured
 a username in unbound.conf, the keys need read permission for the user
 credentials under which the daemon is started.
 The script preserves private keys present in the directory.
-After running the script as root, turn on \fBcontrol\-enable\fR in 
+After running the script as root, turn on \fBcontrol\-enable\fR in
 \fIunbound.conf\fR.
 .SH "STATISTIC COUNTERS"
 The \fIstats\fR command shows a number of statistic counters.
@@ -417,8 +417,8 @@ Average time it took to answer queries that needed recursive processing. Note th
 .TP
 .I threadX.recursion.time.median
 The median of the time it took to answer queries that needed recursive
-processing.  The median means that 50% of the user queries were answered in 
-less than this time.  Because of big outliers (usually queries to non 
+processing.  The median means that 50% of the user queries were answered in
+less than this time.  Because of big outliers (usually queries to non
 responsive servers), the average can be bigger than the median.  This median
 has been calculated by interpolation from a histogram.
 .TP
@@ -544,32 +544,32 @@ The total number of queries over all threads with query opcode QUERY.
 Also printed for other opcodes, UPDATE, ...
 .TP
 .I num.query.tcp
-Number of queries that were made using TCP towards the unbound server.
+Number of queries that were made using TCP towards the Unbound server.
 .TP
 .I num.query.tcpout
-Number of queries that the unbound server made using TCP outgoing towards
+Number of queries that the Unbound server made using TCP outgoing towards
 other servers.
 .TP
 .I num.query.tls
-Number of queries that were made using TLS towards the unbound server.
+Number of queries that were made using TLS towards the Unbound server.
 These are also counted in num.query.tcp, because TLS uses TCP.
 .TP
 .I num.query.tls.resume
 Number of TLS session resumptions, these are queries over TLS towards
-the unbound server where the client negotiated a TLS session resumption key.
+the Unbound server where the client negotiated a TLS session resumption key.
 .TP
 .I num.query.https
-Number of queries that were made using HTTPS towards the unbound server.
+Number of queries that were made using HTTPS towards the Unbound server.
 These are also counted in num.query.tcp and num.query.tls, because HTTPS
 uses TLS and TCP.
 .TP
 .I num.query.ipv6
-Number of queries that were made using IPv6 towards the unbound server.
+Number of queries that were made using IPv6 towards the Unbound server.
 .TP
 .I num.query.flags.RD
 The number of queries that had the RD flag set in the header.
 Also printed for flags QR, AA, TC, RA, Z, AD, CD.
-Note that queries with flags QR, AA or TC may have been rejected 
+Note that queries with flags QR, AA or TC may have been rejected
 because of that.
 .TP
 .I num.query.edns.present
@@ -603,7 +603,7 @@ These queries are also included in the num.answer.rcode.NOERROR number.
 Common for AAAA lookups when an A record exists, and no AAAA.
 .TP
 .I num.answer.secure
-Number of answers that were secure.  The answer validated correctly. 
+Number of answers that were secure.  The answer validated correctly.
 The AD bit might have been set in some of these answers, where the client
 signalled (with DO or AD bit in the query) that they were ready to accept
 the AD bit in the answer.
@@ -644,7 +644,7 @@ per delegation point, and their validation status.
 .I dnscrypt_shared_secret.cache.count
 The number of items in the shared secret cache. These are precomputed shared
 secrets for a given client public key/server secret key pair. Shared secrets
-are CPU intensive and this cache allows unbound to avoid recomputing the
+are CPU intensive and this cache allows Unbound to avoid recomputing the
 shared secret when multiple dnscrypt queries are sent from the same client.
 .TP
 .I dnscrypt_nonce.cache.count
@@ -684,16 +684,16 @@ specific cache, after getting processed by the edns client subnet module.
 .TP
 .I num.rpz.action.<rpz_action>
 Number of queries answered using configured RPZ policy, per RPZ action type.
-Possible actions are: nxdomain, nodata, passthru, drop, local_data, disabled,
-and cname_override.
+Possible actions are: nxdomain, nodata, passthru, drop, tcp\-only, local\-data,
+disabled, and cname\-override.
 .SH "FILES"
 .TP
 .I @ub_conf_file@
-unbound configuration file.
+Unbound configuration file.
 .TP
 .I @UNBOUND_RUN_DIR@
 directory with private keys (unbound_server.key and unbound_control.key) and
 self\-signed certificates (unbound_server.pem and unbound_control.pem).
 .SH "SEE ALSO"
-\fIunbound.conf\fR(5), 
+\fIunbound.conf\fR(5),
 \fIunbound\fR(8).
index 4823b9a..94c8ca3 100644 (file)
@@ -1,4 +1,4 @@
-.TH "unbound\-host" "1" "Aug 12, 2021" "NLnet Labs" "unbound 1.13.2"
+.TH "unbound\-host" "1" "Feb 10, 2022" "NLnet Labs" "unbound 1.15.0"
 .\"
 .\" unbound-host.1 -- unbound DNS lookup utility
 .\"
@@ -15,7 +15,7 @@
 .RB [ \-C
 .IR configfile ]
 .RB [ \-vdhr46D ]
-.RB [ \-c 
+.RB [ \-c
 .IR class ]
 .RB [ \-t
 .IR type ]
 .I hostname
 .SH "DESCRIPTION"
 .B Unbound\-host
-uses the unbound validating resolver to query for the hostname and display
-results. With the \fB\-v\fR option it displays validation 
+uses the Unbound validating resolver to query for the hostname and display
+results. With the \fB\-v\fR option it displays validation
 status: secure, insecure, bogus (security failure).
 .P
 By default it reads no configuration file whatsoever.  It attempts to reach
-the internet root servers.  With \fB\-C\fR an unbound config file and with
+the internet root servers.  With \fB\-C\fR an Unbound config file and with
 \fB\-r\fR resolv.conf can be read.
 .P
 The available options are:
@@ -73,7 +73,7 @@ For example \-y "example.com DS 31560 5 1 1CFED84787E6E19CCF9372C1187325972FE546
 .TP
 .B \-D
 Enables DNSSEC validation.  Reads the root anchor from the default configured
-root anchor at the default location, \fI@UNBOUND_ROOTKEY_FILE@\fR. 
+root anchor at the default location, \fI@UNBOUND_ROOTKEY_FILE@\fR.
 .TP
 .B \-f \fIkeyfile
 Reads keys from a file. Every line has a DS or DNSKEY record, in the format
@@ -110,9 +110,9 @@ $ unbound\-host \-v \-y "example.com DS 31560 5 1 1CFED84787E6E19CCF9372C1187325
 .P
 $ unbound\-host \-v \-y "example.com DS 31560 5 1 1CFED84787E6E19CCF9372C1187325972FE546CD" 192.0.2.153
 .SH "EXIT CODE"
-The unbound\-host program exits with status code 1 on error, 
+The unbound\-host program exits with status code 1 on error,
 0 on no error. The data may not be available on exit code 0, exit code 1
 means the lookup encountered a fatal error.
 .SH "SEE ALSO"
-\fIunbound.conf\fR(5), 
+\fIunbound.conf\fR(5),
 \fIunbound\fR(8).
index 82c4e98..723f232 100644 (file)
@@ -1,4 +1,4 @@
-.TH "unbound" "8" "Aug 12, 2021" "NLnet Labs" "unbound 1.13.2"
+.TH "unbound" "8" "Feb 10, 2022" "NLnet Labs" "unbound 1.15.0"
 .\"
 .\" unbound.8 -- unbound manual
 .\"
@@ -9,7 +9,7 @@
 .\"
 .SH "NAME"
 .B unbound
-\- Unbound DNS validating resolver 1.13.2.
+\- Unbound DNS validating resolver 1.15.0.
 .SH "SYNOPSIS"
 .B unbound
 .RB [ \-h ]
@@ -57,7 +57,7 @@ The available options are:
 Show the version number and commandline option help, and exit.
 .TP
 .B \-c\fI cfgfile
-Set the config file with settings for unbound to read instead of reading the
+Set the config file with settings for Unbound to read instead of reading the
 file at the default location, @ub_conf_file@. The syntax is
 described in \fIunbound.conf\fR(5).
 .TP
@@ -70,7 +70,7 @@ or to syslog, but the log messages are printed to stderr all the time.
 .TP
 .B \-p
 Don't use a pidfile.  This argument should only be used by supervision
-systems which can ensure that only one instance of unbound will run
+systems which can ensure that only one instance of Unbound will run
 concurrently.
 .TP
 .B \-v
index ec4762e..55b97cc 100644 (file)
@@ -1,4 +1,4 @@
-.TH "unbound.conf" "5" "Aug 12, 2021" "NLnet Labs" "unbound 1.13.2"
+.TH "unbound.conf" "5" "Feb 10, 2022" "NLnet Labs" "unbound 1.15.0"
 .\"
 .\" unbound.conf.5 -- unbound.conf manual
 .\"
@@ -68,7 +68,7 @@ requestlist statistics are printed for every interval (but can be 0).
 This is because the median calculation requires data to be present.
 .TP
 .B statistics\-cumulative: \fI<yes or no>
-If enabled, statistics are cumulative since starting unbound, without clearing
+If enabled, statistics are cumulative since starting Unbound, without clearing
 the statistics counters after logging the statistics. Default is no.
 .TP
 .B extended\-statistics: \fI<yes or no>
@@ -100,7 +100,7 @@ Same as interface: (for ease of compatibility with nsd.conf).
 Listen on all addresses on all (current and future) interfaces, detect the
 source interface on UDP queries and copy them to replies.  This is a lot like
 ip\-transparent, but this option services all interfaces whilst with
-ip\-transparent you can select which (future) interfaces unbound provides
+ip\-transparent you can select which (future) interfaces Unbound provides
 service on.  This feature is experimental, and needs support in your OS for
 particular socket options.  Default value is no.
 .TP
@@ -118,7 +118,7 @@ sent via a random outgoing interface to counter spoofing.
 If an IPv6 netblock is specified instead of an individual IPv6 address,
 outgoing UDP queries will use a randomised source address taken from the
 netblock to counter spoofing. Requires the IPv6 netblock to be routed to the
-host running unbound, and requires OS support for unprivileged non-local binds
+host running Unbound, and requires OS support for unprivileged non-local binds
 (currently only supported on Linux). Several netblocks may be specified with
 multiple
 .B outgoing\-interface:
@@ -138,7 +138,7 @@ numbers need extra resources from the operating system.  For performance a
 very large value is best, use libevent to make this possible.
 .TP
 .B outgoing\-port\-permit: \fI<port number or range>
-Permit unbound to open this port or range of ports for use to send queries.
+Permit Unbound to open this port or range of ports for use to send queries.
 A larger number of permitted outgoing ports increases resilience against
 spoofing attempts. Make sure these ports are not needed by other daemons.
 By default only ports above 1024 that have not been assigned by IANA are used.
@@ -151,8 +151,8 @@ processing starts with the non IANA allocated ports above 1024 in the set
 of allowed ports.
 .TP
 .B outgoing\-port\-avoid: \fI<port number or range>
-Do not permit unbound to open this port or range of ports for use to send
-queries. Use this to make sure unbound does not grab a port that another
+Do not permit Unbound to open this port or range of ports for use to send
+queries. Use this to make sure Unbound does not grab a port that another
 daemon needs. The port is avoided on all outgoing interfaces, both IP4 and IP6.
 By default only ports above 1024 that have not been assigned by IANA are used.
 Give a port number or a range of the form "low\-high", without spaces.
@@ -253,7 +253,7 @@ If not 0, then set the SO_RCVBUF socket option to get more buffer
 space on UDP port 53 incoming queries.  So that short spikes on busy
 servers do not drop packets (see counter in netstat \-su).  Default is
 0 (use system value).  Otherwise, the number of bytes to ask for, try
-"4m" on a busy server.  The OS caps it at a maximum, on linux unbound
+"4m" on a busy server.  The OS caps it at a maximum, on linux Unbound
 needs root permission to bypass the limit, or the admin can use sysctl
 net.core.rmem_max.  On BSD change kern.ipc.maxsockbuf in /etc/sysctl.conf.
 On OpenBSD change header and recompile kernel. On Solaris ndd \-set
@@ -266,7 +266,7 @@ in answer traffic, otherwise 'send: resource temporarily unavailable'
 can get logged, the buffer overrun is also visible by netstat \-su.
 Default is 0 (use system value).  Specify the number of bytes to ask
 for, try "4m" on a very busy server.  The OS caps it at a maximum, on
-linux unbound needs root permission to bypass the limit, or the admin
+linux Unbound needs root permission to bypass the limit, or the admin
 can use sysctl net.core.wmem_max.  On BSD, Solaris changes are similar
 to so\-rcvbuf.
 .TP
@@ -283,18 +283,18 @@ At extreme load it could be better to turn it off to distribute the queries
 evenly, reported for Linux systems (4.4.x).
 .TP
 .B ip\-transparent: \fI<yes or no>
-If yes, then use IP_TRANSPARENT socket option on sockets where unbound
+If yes, then use IP_TRANSPARENT socket option on sockets where Unbound
 is listening for incoming traffic.  Default no.  Allows you to bind to
 non\-local interfaces.  For example for non\-existent IP addresses that
 are going to exist later on, with host failover configuration.  This is
 a lot like interface\-automatic, but that one services all interfaces
-and with this option you can select which (future) interfaces unbound
-provides service on.  This option needs unbound to be started with root
+and with this option you can select which (future) interfaces Unbound
+provides service on.  This option needs Unbound to be started with root
 permissions on some systems.  The option uses IP_BINDANY on FreeBSD systems
 and SO_BINDANY on OpenBSD systems.
 .TP
 .B ip\-freebind: \fI<yes or no>
-If yes, then use IP_FREEBIND socket option on sockets where unbound
+If yes, then use IP_FREEBIND socket option on sockets where Unbound
 is listening to incoming traffic.  Default no.  Allows you to bind to
 IP addresses that are nonlocal or do not exist, like when the network
 interface or IP address is down.  Exists only on Linux, where the similar
@@ -449,7 +449,9 @@ advertised timeout.
 .TP
 .B tcp\-upstream: \fI<yes or no>
 Enable or disable whether the upstream queries use TCP only for transport.
-Default is no.  Useful in tunneling scenarios.
+Default is no.  Useful in tunneling scenarios. If set to no you can specify
+TCP transport only for selected forward or stub zones using forward-tcp-upstream
+or stub-tcp-upstream respectively.
 .TP
 .B udp\-upstream\-without\-downstream: \fI<yes or no>
 Enable udp upstream even if do-udp is no.  Default is no, and this does not
@@ -522,7 +524,7 @@ service.  Can list multiple, each on a new statement.
 .TP
 .B tls-session-ticket-keys: \fI<file>
 If not "", lists files with 80 bytes of random contents that are used to
-perform TLS session resumption for clients using the unbound server.
+perform TLS session resumption for clients using the Unbound server.
 These files contain the secret key for the TLS session tickets.
 First key use to encrypt and decrypt TLS session tickets.
 Other keys use to decrypt only.  With this you can roll over to new keys,
@@ -604,8 +606,8 @@ Enable or disable systemd socket activation.
 Default is no.
 .TP
 .B do\-daemonize: \fI<yes or no>
-Enable or disable whether the unbound server forks into the background as
-a daemon.  Set the value to \fIno\fR when unbound runs as systemd service.
+Enable or disable whether the Unbound server forks into the background as
+a daemon.  Set the value to \fIno\fR when Unbound runs as systemd service.
 Default is yes.
 .TP
 .B tcp\-connection\-limit: \fI<IP netblock> <limit>
@@ -632,7 +634,7 @@ what almost all clients need).  Nonrecursive queries are refused.
 .IP
 The \fIallow\fR action does allow nonrecursive queries to access the
 local\-data that is configured.  The reason is that this does not involve
-the unbound server recursive lookup algorithm, and static data is served
+the Unbound server recursive lookup algorithm, and static data is served
 in the reply.  This supports normal operations where nonrecursive queries
 are made for the authoritative data.  For nonrecursive queries any replies
 from the dynamic cache are refused.
@@ -704,7 +706,7 @@ to chroot and dropping permissions. This allows the pidfile to be
 Unbound is not able to remove the pidfile after termination when it is located
 outside of the chroot directory.
 .IP
-Additionally, unbound may need to access /dev/urandom (for entropy)
+Additionally, Unbound may need to access /dev/urandom (for entropy)
 from inside the chroot.
 .IP
 If given a chroot is done to the given directory. By default chroot is
@@ -738,7 +740,7 @@ The logfile is reopened (for append) when the config file is reread, on
 SIGHUP.
 .TP
 .B use\-syslog: \fI<yes or no>
-Sets unbound to send log messages to the syslogd, using
+Sets Unbound to send log messages to the syslogd, using
 \fIsyslog\fR(3).
 The log facility LOG_DAEMON is used, with identity "unbound".
 The logfile setting is overridden when use\-syslog is turned on.
@@ -748,7 +750,7 @@ The default is to log to syslog.
 If "" is given (default), then the name of the executable, usually "unbound"
 is used to report to the log.  Enter a string to override it
 with that, which is useful on systems that run more than one instance of
-unbound, with different configurations, so that the logs can be easily
+Unbound, with different configurations, so that the logs can be easily
 distinguished against.
 .TP
 .B log\-time\-ascii: \fI<yes or no>
@@ -827,12 +829,12 @@ with ascii_ prefix and then an ascii string.
 If enabled trustanchor.unbound queries are refused.
 .TP
 .B target\-fetch\-policy: \fI<"list of numbers">
-Set the target fetch policy used by unbound to determine if it should fetch
+Set the target fetch policy used by Unbound to determine if it should fetch
 nameserver target addresses opportunistically. The policy is described per
 dependency depth.
 .IP
 The number of values determines the maximum dependency depth
-that unbound will pursue in answering a query.
+that Unbound will pursue in answering a query.
 A value of \-1 means to fetch all targets opportunistically for that dependency
 depth. A value of 0 means to fetch on demand only. A positive value fetches
 that many targets opportunistically.
@@ -926,7 +928,7 @@ This option only has effect when qname-minimisation is enabled. Default is no.
 .B aggressive\-nsec: \fI<yes or no>
 Aggressive NSEC uses the DNSSEC NSEC chain to synthesize NXDOMAIN
 and other denials, using information from previous NXDOMAINs answers.
-Default is no.  It helps to reduce the query rate towards targets that get
+Default is yes.  It helps to reduce the query rate towards targets that get
 a very high nonexistent name lookup rate.
 .TP
 .B private\-address: \fI<IP address or subnet>
@@ -983,7 +985,7 @@ a little more CPU.  Also if the cache is set to 0, it is no use. Default is no.
 .TP
 .B deny\-any: \fI<yes or no>
 If yes, deny queries of type ANY with an empty response.  Default is no.
-If disabled, unbound responds with a short list of resource records if some
+If disabled, Unbound responds with a short list of resource records if some
 can be found in the cache and makes the upstream type ANY query if there
 are none.
 .TP
@@ -1043,7 +1045,7 @@ File with trust anchor for one zone, which is tracked with RFC5011 probes.
 The probes are run several times per month, thus the machine must be online
 frequently.  The initial file can be one with contents as described in
 \fBtrust\-anchor\-file\fR.  The file is written to when the anchor is updated,
-so the unbound user must have write permission.  Write permission to the file,
+so the Unbound user must have write permission.  Write permission to the file,
 but also to the directory it is in (to create a temporary file, which is
 necessary to deal with filesystem full events), it must also be inside the
 chroot (if that is used).
@@ -1129,7 +1131,7 @@ the verbosity setting.  Default is 0, off.  At 1, for every user query
 that fails a line is printed to the logs.  This way you can monitor what
 happens with validation.  Use a diagnosis tool, such as dig or drill,
 to find out why validation is failing for these queries.  At 2, not only
-the query that failed is printed but also the reason why unbound thought
+the query that failed is printed but also the reason why Unbound thought
 it was wrong and which server sent the faulty data.
 .TP
 .B val\-permissive\-mode: \fI<yes or no>
@@ -1141,15 +1143,15 @@ is set in replies. Also logging is performed as for full validation.
 The default value is "no".
 .TP
 .B ignore\-cd\-flag: \fI<yes or no>
-Instruct unbound to ignore the CD flag from clients and refuse to
+Instruct Unbound to ignore the CD flag from clients and refuse to
 return bogus answers to them.  Thus, the CD (Checking Disabled) flag
 does not disable checking any more.  This is useful if legacy (w2008)
 servers that set the CD flag but cannot validate DNSSEC themselves are
-the clients, and then unbound provides them with DNSSEC protection.
+the clients, and then Unbound provides them with DNSSEC protection.
 The default value is "no".
 .TP
 .B serve\-expired: \fI<yes or no>
-If enabled, unbound attempts to serve old responses from cache with a
+If enabled, Unbound attempts to serve old responses from cache with a
 TTL of \fBserve\-expired\-reply\-ttl\fR in the response without waiting for the
 actual resolution to finish.  The actual resolution answer ends up in the cache
 later on.  Default is "no".
@@ -1180,14 +1182,14 @@ RFC 8767 is 1800.  Setting this to 0 will disable this
 behavior.  Default is 0.
 .TP
 .B serve\-original\-ttl: \fI<yes or no>
-If enabled, unbound will always return the original TTL as received from
+If enabled, Unbound will always return the original TTL as received from
 the upstream name server rather than the decrementing TTL as
-stored in the cache.  This feature may be useful if unbound serves as a 
-front-end to a hidden authoritative name server. Enabling this feature does 
-not impact cache expiry, it only changes the TTL unbound embeds in responses to 
+stored in the cache.  This feature may be useful if Unbound serves as a
+front-end to a hidden authoritative name server. Enabling this feature does
+not impact cache expiry, it only changes the TTL Unbound embeds in responses to
 queries. Note that enabling this feature implicitly disables enforcement of
-the configured minimum and maximum TTL, as it is assumed users who enable this 
-feature do not want unbound to change the TTL obtained from an upstream server. 
+the configured minimum and maximum TTL, as it is assumed users who enable this
+feature do not want Unbound to change the TTL obtained from an upstream server.
 Thus, the values set using \fBcache\-min\-ttl\fR and \fBcache\-max\-ttl\fR are
 ignored.
 Default is "no".
@@ -1248,11 +1250,11 @@ or gigabytes (1024*1024 bytes in a megabyte).
 .TP
 .B unblock\-lan\-zones: \fI<yes or no>
 Default is disabled.  If enabled, then for private address space,
-the reverse lookups are no longer filtered.  This allows unbound when
+the reverse lookups are no longer filtered.  This allows Unbound when
 running as dns service on a host where it provides service for that host,
 to put out all of the queries for the 'lan' upstream.  When enabled,
 only localhost, 127.0.0.1 reverse and ::1 reverse zones are configured
-with default local zones.  Disable the option when unbound is running
+with default local zones.  Disable the option when Unbound is running
 as a (DHCP-) DNS network resolver for a group of machines, where such
 lookups should be filtered (RFC compliance), this also stops potential
 data leakage about the local network to the upstream DNS servers.
@@ -1356,7 +1358,7 @@ Breaks out of that view and moves towards the global local zones for answer
 to the query.  If the view first is no, it'll resolve normally.  If view first
 is enabled, it'll break perform that step and check the global answers.
 For when the view has view specific overrides but some zone has to be
-answered from global local zone contents. 
+answered from global local zone contents.
 .TP 10
 \h'5'\fInodefault\fR
 Used to turn off default contents for AS112 zones. The other types
@@ -1365,13 +1367,13 @@ has no other effect than turning off default contents for the
 given zone.  Use \fInodefault\fR if you use exactly that zone, if you want to
 use a subzone, use \fItransparent\fR.
 .P
-The default zones are localhost, reverse 127.0.0.1 and ::1, the onion, test,
-invalid and the AS112 zones. The AS112 zones are reverse DNS zones for
-private use and reserved IP addresses for which the servers on the internet
-cannot provide correct answers. They are configured by default to give
-nxdomain (no reverse information) answers. The defaults can be turned off
-by specifying your own local\-zone of that name, or using the 'nodefault'
-type. Below is a list of the default zone contents.
+The default zones are localhost, reverse 127.0.0.1 and ::1, the home.arpa,
+the onion, test, invalid and the AS112 zones. The AS112 zones are reverse
+DNS zones for private use and reserved IP addresses for which the servers
+on the internet cannot provide correct answers. They are configured by
+default to give nxdomain (no reverse information) answers. The defaults
+can be turned off by specifying your own local\-zone of that name, or
+using the 'nodefault' type. Below is a list of the default zone contents.
 .TP 10
 \h'5'\fIlocalhost\fR
 The IP4 and IP6 localhost information is given. NS and SOA records are provided
@@ -1412,6 +1414,15 @@ local\-data: "1.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.
     PTR localhost."
 .fi
 .TP 10
+\h'5'\fIhome.arpa (RFC 8375)\fR
+Default content:
+.nf
+local\-zone: "home.arpa." static
+local\-data: "home.arpa. 10800 IN NS localhost."
+local\-data: "home.arpa. 10800 IN
+    SOA localhost. nobody.invalid. 1 3600 1200 604800 10800"
+.fi
+.TP 10
 \h'5'\fIonion (RFC 7686)\fR
 Default content:
 .nf
@@ -1591,8 +1602,9 @@ query names, but not spoofed reflection floods.  Cached responses are not
 ratelimited by this setting.  The zone of the query is determined by examining
 the nameservers for it, the zone name is used to keep track of the rate.
 For example, 1000 may be a suitable value to stop the server from being
-overloaded with random names, and keeps unbound from sending traffic to the
-nameservers for those zones.
+overloaded with random names, and keeps Unbound from sending traffic to the
+nameservers for those zones.  Configured forwarders are excluded from
+ratelimiting.
 .TP 5
 .B ratelimit\-size: \fI<memory size>
 Give the size of the data structure in which the current ongoing rates are
@@ -1614,6 +1626,15 @@ This can make ordinary queries complete (if repeatedly queried for),
 and enter the cache, whilst also mitigating the traffic flow by the
 factor given.
 .TP 5
+.B ratelimit\-backoff: \fI<yes or no>
+If enabled, the ratelimit is treated as a hard failure instead of the default
+maximum allowed constant rate.  When the limit is reached, traffic is
+ratelimited and demand continues to be kept track of for a 2 second rate
+window.  No traffic is allowed, except for ratelimit\-factor, until demand
+decreases below the configured ratelimit for a 2 second rate window.  Useful to
+set ratelimit to a suspicious rate to aggressively limit unusually high
+traffic.  Default is off.
+.TP 5
 .B ratelimit\-for\-domain: \fI<domain> <number qps or 0>
 Override the global ratelimit for an exact match domain name with the listed
 number.  You can give this for any number of names.  For example, for
@@ -1630,7 +1651,7 @@ to use different settings for a top\-level\-domain and subdomains.
 A value of 0 will disable ratelimiting for domain names that end in this name.
 .TP 5
 .B ip\-ratelimit: \fI<number or 0>
-Enable global ratelimiting of queries accepted per ip address.
+Enable global ratelimiting of queries accepted per IP address.
 If 0, the default, it is disabled.  This option is experimental at this time.
 The ratelimit is in queries per second that are allowed.  More queries are
 completely dropped and will not receive a reply, SERVFAIL or otherwise.
@@ -1657,6 +1678,20 @@ This can make ordinary queries complete (if repeatedly queried for),
 and enter the cache, whilst also mitigating the traffic flow by the
 factor given.
 .TP 5
+.B ip\-ratelimit\-backoff: \fI<yes or no>
+If enabled, the ratelimit is treated as a hard failure instead of the default
+maximum allowed constant rate.  When the limit is reached, traffic is
+ratelimited and demand continues to be kept track of for a 2 second rate
+window.  No traffic is allowed, except for ip\-ratelimit\-factor, until demand
+decreases below the configured ratelimit for a 2 second rate window.  Useful to
+set ip\-ratelimit to a suspicious rate to aggressively limit unusually high
+traffic.  Default is off.
+.TP 5
+.B outbound\-msg\-retry: \fI<number>
+The number of retries Unbound will do in case of a non positive response is
+received. If a forward nameserver is used, this is the number of retries per
+forward nameserver in case of throwaway response.
+.TP 5
 .B fast\-server\-permil: \fI<number>
 Specify how many times out of 1000 to pick from the set of fastest servers.
 0 turns the feature off.  A value of 900 would pick from the fastest
@@ -1686,7 +1721,7 @@ In the
 .B remote\-control:
 clause are the declarations for the remote control facility.  If this is
 enabled, the \fIunbound\-control\fR(8) utility can be used to send
-commands to the running unbound server.  The server uses these clauses
+commands to the running Unbound server.  The server uses these clauses
 to setup TLSv1 security for the connection.  The
 \fIunbound\-control\fR(8) utility also reads the \fBremote\-control\fR
 section for options.  To setup the correct self\-signed certificates use the
@@ -1706,7 +1741,7 @@ the server for the change to take effect.
 .IP
 If you set it to an absolute path, a local socket is used.  The local socket
 does not use the certificates and keys, so those files need not be present.
-To restrict access, unbound sets permissions on the file to the user and
+To restrict access, Unbound sets permissions on the file to the user and
 group that is configured, the access bits are set to allow the group members
 to access the control socket file.  Put users that need to access the socket
 in the that group.  To restrict access further, create a directory to put
@@ -1726,12 +1761,12 @@ and the value of this option is ignored.
 .B server\-key\-file: \fI<private key file>
 Path to the server private key, by default unbound_server.key.
 This file is generated by the \fIunbound\-control\-setup\fR utility.
-This file is used by the unbound server, but not by \fIunbound\-control\fR.
+This file is used by the Unbound server, but not by \fIunbound\-control\fR.
 .TP 5
 .B server\-cert\-file: \fI<certificate file.pem>
 Path to the server self signed certificate, by default unbound_server.pem.
 This file is generated by the \fIunbound\-control\-setup\fR utility.
-This file is used by the unbound server, and also by \fIunbound\-control\fR.
+This file is used by the Unbound server, and also by \fIunbound\-control\fR.
 .TP 5
 .B control\-key\-file: \fI<private key file>
 Path to the control client private key, by default unbound_control.key.
@@ -1749,24 +1784,24 @@ There may be multiple
 .B stub\-zone:
 clauses. Each with a name: and zero or more hostnames or IP addresses.
 For the stub zone this list of nameservers is used. Class IN is assumed.
-The servers should be authority servers, not recursors; unbound performs
+The servers should be authority servers, not recursors; Unbound performs
 the recursive processing itself for stub zones.
 .P
 The stub zone can be used to configure authoritative data to be used
 by the resolver that cannot be accessed using the public internet servers.
 This is useful for company\-local data or private zones. Setup an
 authoritative server on a different host (or different port). Enter a config
-entry for unbound with
+entry for Unbound with
 .B stub\-addr:
 <ip address of host[@port]>.
-The unbound resolver can then access the data, without referring to the
+The Unbound resolver can then access the data, without referring to the
 public internet for it.
 .P
 This setup allows DNSSEC signed zones to be served by that
 authoritative server, in which case a trusted key entry with the public key
-can be put in config, so that unbound can validate the data and set the AD
+can be put in config, so that Unbound can validate the data and set the AD
 bit on replies for the private zone (authoritative servers do not set the
-AD bit).  This setup makes unbound capable of answering queries for the
+AD bit).  This setup makes Unbound capable of answering queries for the
 private zone, and can even set the AD bit ('authentic'), but the AA
 ('authoritative') bit is not set on these replies.
 .P
@@ -1774,20 +1809,26 @@ Consider adding \fBserver:\fR statements for \fBdomain\-insecure:\fR and
 for \fBlocal\-zone:\fI name nodefault\fR for the zone if it is a locally
 served zone.  The insecure clause stops DNSSEC from invalidating the
 zone.  The local zone nodefault (or \fItransparent\fR) clause makes the
-(reverse\-) zone bypass unbound's filtering of RFC1918 zones.
+(reverse\-) zone bypass Unbound's filtering of RFC1918 zones.
 .TP
 .B name: \fI<domain name>
-Name of the stub zone.
+Name of the stub zone. This is the full domain name of the zone.
 .TP
 .B stub\-host: \fI<domain name>
 Name of stub zone nameserver. Is itself resolved before it is used.
+To use a nondefault port for DNS communication append '@' with the port number.
+If tls is enabled, then you can append a '#' and a name, then it'll check the
+tls authentication certificates with that name.  If you combine the '@'
+and '#', the '@' comes first.  If only '#' is used the default port is the
+configured tls\-port.
 .TP
 .B stub\-addr: \fI<IP address>
 IP address of stub zone nameserver. Can be IP 4 or IP 6.
 To use a nondefault port for DNS communication append '@' with the port number.
-If tls is enabled, then you can append a '#' and a name, then it'll check
-the tls authentication certificates with that name.  If you combine
-the '@' and '#', the '@' comes first.
+If tls is enabled, then you can append a '#' and a name, then it'll check the
+tls authentication certificates with that name.  If you combine the '@'
+and '#', the '@' comes first.  If only '#' is used the default port is the
+configured tls\-port.
 .TP
 .B stub\-prime: \fI<yes or no>
 This option is by default no.  If enabled it performs NS set priming,
@@ -1808,6 +1849,10 @@ Default is no.
 .B stub\-ssl\-upstream: \fI<yes or no>
 Alternate syntax for \fBstub\-tls\-upstream\fR.
 .TP
+.B stub\-tcp\-upstream: \fI<yes or no>
+If it is set to "yes" then upstream queries use TCP only for transport regardless of global flag tcp-upstream.
+Default is no.
+.TP
 .B stub\-no\-cache: \fI<yes or no>
 Default is no.  If enabled, data inside the stub is not cached.  This is
 useful when you want immediate changes to be visible.
@@ -1819,10 +1864,10 @@ clauses. Each with a \fBname:\fR and zero or more hostnames or IP
 addresses.  For the forward zone this list of nameservers is used to
 forward the queries to. The servers listed as \fBforward\-host:\fR and
 \fBforward\-addr:\fR have to handle further recursion for the query.  Thus,
-those servers are not authority servers, but are (just like unbound is)
-recursive servers too; unbound does not perform recursion itself for the
+those servers are not authority servers, but are (just like Unbound is)
+recursive servers too; Unbound does not perform recursion itself for the
 forward zone, it lets the remote server do it.  Class IN is assumed.
-CNAMEs are chased by unbound itself, asking the remote server for every
+CNAMEs are chased by Unbound itself, asking the remote server for every
 name in the indirection chain, to protect the local cache from illegal
 indirect referenced items.
 A forward\-zone entry with name "." and a forward\-addr target will
@@ -1830,17 +1875,23 @@ forward all queries to that other server (unless it can answer from
 the cache).
 .TP
 .B name: \fI<domain name>
-Name of the forward zone.
+Name of the forward zone. This is the full domain name of the zone.
 .TP
 .B forward\-host: \fI<domain name>
 Name of server to forward to. Is itself resolved before it is used.
+To use a nondefault port for DNS communication append '@' with the port number.
+If tls is enabled, then you can append a '#' and a name, then it'll check the
+tls authentication certificates with that name.  If you combine the '@'
+and '#', the '@' comes first.  If only '#' is used the default port is the
+configured tls\-port.
 .TP
 .B forward\-addr: \fI<IP address>
 IP address of server to forward to. Can be IP 4 or IP 6.
 To use a nondefault port for DNS communication append '@' with the port number.
-If tls is enabled, then you can append a '#' and a name, then it'll check
-the tls authentication certificates with that name.  If you combine
-the '@' and '#', the '@' comes first.
+If tls is enabled, then you can append a '#' and a name, then it'll check the
+tls authentication certificates with that name.  If you combine the '@'
+and '#', the '@' comes first.  If only '#' is used the default port is the
+configured tls\-port.
 .IP
 At high verbosity it logs the TLS certificate, with TLS enabled.
 If you leave out the '#' and auth name from the forward\-addr, any
@@ -1848,7 +1899,7 @@ name is accepted.  The cert must also match a CA from the tls\-cert\-bundle.
 .TP
 .B forward\-first: \fI<yes or no>
 If a forwarded query is met with a SERVFAIL error, and this option is
-enabled, unbound will fall back to normal recursive resolution for this
+enabled, Unbound will fall back to normal recursive resolution for this
 query as if no query forwarding had been specified.  The default is "no".
 .TP
 .B forward\-tls\-upstream: \fI<yes or no>
@@ -1860,6 +1911,10 @@ load CA certs, otherwise the connections cannot be authenticated.
 .B forward\-ssl\-upstream: \fI<yes or no>
 Alternate syntax for \fBforward\-tls\-upstream\fR.
 .TP
+.B forward\-tcp\-upstream: \fI<yes or no>
+If it is set to "yes" then upstream queries use TCP only for transport regardless of global flag tcp-upstream.
+Default is no.
+.TP
 .B forward\-no\-cache: \fI<yes or no>
 Default is no.  If enabled, data inside the forward is not cached.  This is
 useful when you want immediate changes to be visible.
@@ -1870,7 +1925,7 @@ have a \fBname:\fR.  There can be multiple ones, by listing multiple auth\-zone
 The authority zone with the name closest to the name looked up is used.
 Authority zones are processed after \fBlocal\-zones\fR and before
 cache (\fBfor\-downstream:\fR \fIyes\fR), and when used in this manner
-make unbound respond like an authority server.  Authority zones are also
+make Unbound respond like an authority server.  Authority zones are also
 processed after cache, just before going to the network to fetch
 information for recursion (\fBfor\-upstream:\fR \fIyes\fR), and when used
 in this manner provide a local copy of an authority server that speeds up
@@ -1931,25 +1986,25 @@ file is downloaded when notified.  The primaries from primary: statements are
 allowed notify by default.
 .TP
 .B fallback\-enabled: \fI<yes or no>
-Default no.  If enabled, unbound falls back to querying the internet as
+Default no.  If enabled, Unbound falls back to querying the internet as
 a resolver for this zone when lookups fail.  For example for DNSSEC
 validation failures.
 .TP
 .B for\-downstream: \fI<yes or no>
-Default yes.  If enabled, unbound serves authority responses to
-downstream clients for this zone.  This option makes unbound behave, for
+Default yes.  If enabled, Unbound serves authority responses to
+downstream clients for this zone.  This option makes Unbound behave, for
 the queries with names in this zone, like one of the authority servers for
-that zone.  Turn it off if you want unbound to provide recursion for the
+that zone.  Turn it off if you want Unbound to provide recursion for the
 zone but have a local copy of zone data.  If for\-downstream is no and
-for\-upstream is yes, then unbound will DNSSEC validate the contents of the
+for\-upstream is yes, then Unbound will DNSSEC validate the contents of the
 zone before serving the zone contents to clients and store validation
 results in the cache.
 .TP
 .B for\-upstream: \fI<yes or no>
-Default yes.  If enabled, unbound fetches data from this data collection
+Default yes.  If enabled, Unbound fetches data from this data collection
 for answering recursion queries.  Instead of sending queries over the internet
 to the authority servers for this zone, it'll fetch the data directly from
-the zone data.  Turn it on when you want unbound to provide recursion for
+the zone data.  Turn it on when you want Unbound to provide recursion for
 downstream clients, and use the zone data as a local copy to speed up lookups.
 .TP
 .B zonemd\-check: \fI<yes or no>
@@ -1973,14 +2028,14 @@ a ZONEMD is always a failure, also for nonDNSSEC signed zones.
 .TP
 .B zonefile: \fI<filename>
 The filename where the zone is stored.  If not given then no zonefile is used.
-If the file does not exist or is empty, unbound will attempt to fetch zone
+If the file does not exist or is empty, Unbound will attempt to fetch zone
 data (eg. from the primary servers).
 .SS "View Options"
 .LP
 There may be multiple
 .B view:
 clauses. Each with a \fBname:\fR and zero or more \fBlocal\-zone\fR and
-\fBlocal\-data\fR elements. Views can also contain view\-first, 
+\fBlocal\-data\fR elements. Views can also contain view\-first,
 response\-ip, response\-ip\-data and local\-data\-ptr elements.
 View can be mapped to requests by specifying the
 view name in an \fBaccess\-control\-view\fR element. Options from matching
@@ -2073,9 +2128,9 @@ underneath the name given.
 The
 .B dnscrypt:
 clause gives the settings of the dnscrypt channel. While those options are
-available, they are only meaningful if unbound was compiled with
+available, they are only meaningful if Unbound was compiled with
 \fB\-\-enable\-dnscrypt\fR.
-Currently certificate and secret/public keys cannot be generated by unbound.
+Currently certificate and secret/public keys cannot be generated by Unbound.
 You can use dnscrypt-wrapper to generate those: https://github.com/cofyc/\
 dnscrypt-wrapper/blob/master/README.md#usage
 .TP
@@ -2194,7 +2249,7 @@ of 0 is always accepted. Default is 0.
 .TP
 .B min\-client\-subnet\-ipv4: \fI<number>\fR
 Specifies the minimum prefix length of the IPv4 source mask we are willing to
-accept in queries. Shorter source masks result in REFUSED answers. Source mask 
+accept in queries. Shorter source masks result in REFUSED answers. Source mask
 of 0 is always accepted. Default is 0.
 .TP
 .B max\-ecs\-tree\-size\-ipv4: \fI<number>\fR
@@ -2207,12 +2262,13 @@ This number applies for each qname/qclass/qtype tuple. Defaults to 100.
 .SS "Opportunistic IPsec Support Module Options"
 .LP
 The IPsec module must be configured in the \fBmodule\-config:\fR "ipsecmod
-validator iterator" directive and be compiled into the daemon to be
-enabled.  These settings go in the \fBserver:\fR section.
+validator iterator" directive and be compiled into Unbound by using
+\fB\-\-enable\-ipsecmod\fR to be enabled.
+These settings go in the \fBserver:\fR section.
 .LP
-When unbound receives an A/AAAA query that is not in the cache and finds a
+When Unbound receives an A/AAAA query that is not in the cache and finds a
 valid answer, it will withhold returning the answer and instead will generate
-an IPSECKEY subquery for the same domain name.  If an answer was found, unbound
+an IPSECKEY subquery for the same domain name.  If an answer was found, Unbound
 will call an external hook passing the following arguments:
 .TP 10
 \h'5'\fIQNAME\fR
@@ -2241,19 +2297,19 @@ relevant for opportunistic IPsec.
 .B ipsecmod-enabled: \fI<yes or no>\fR
 Specifies whether the IPsec module is enabled or not.  The IPsec module still
 needs to be defined in the \fBmodule\-config:\fR directive.  This option
-facilitates turning on/off the module without restarting/reloading unbound.
+facilitates turning on/off the module without restarting/reloading Unbound.
 Defaults to yes.
 .TP
 .B ipsecmod\-hook: \fI<filename>\fR
-Specifies the external hook that unbound will call with \fIsystem\fR(3).  The
+Specifies the external hook that Unbound will call with \fIsystem\fR(3).  The
 file can be specified as an absolute/relative path.  The file needs the proper
-permissions to be able to be executed by the same user that runs unbound.  It
+permissions to be able to be executed by the same user that runs Unbound.  It
 must be present when the IPsec module is defined in the \fBmodule\-config:\fR
 directive.
 .TP
 .B ipsecmod-strict: \fI<yes or no>\fR
-If enabled unbound requires the external hook to return a success value of 0.
-Failing to do so unbound will reply with SERVFAIL.  The A/AAAA answer will also
+If enabled Unbound requires the external hook to return a success value of 0.
+Failing to do so Unbound will reply with SERVFAIL.  The A/AAAA answer will also
 not be cached.  Defaults to no.
 .TP
 .B ipsecmod\-max-ttl: \fI<seconds>\fR
@@ -2261,7 +2317,7 @@ Time to live maximum for A/AAAA cached records after calling the external hook.
 Defaults to 3600.
 .TP
 .B ipsecmod-ignore-bogus: \fI<yes or no>\fR
-Specifies the behaviour of unbound when the IPSECKEY answer is bogus.  If set
+Specifies the behaviour of Unbound when the IPSECKEY answer is bogus.  If set
 to yes, the hook will be called and the A/AAAA answer will be returned to the
 client.  If set to no, the hook will not be called and the answer to the
 A/AAAA query will be SERVFAIL.  Mainly used for testing.  Defaults to no.
@@ -2288,7 +2344,7 @@ If Unbound cannot even find an answer in the backend, it resolves the
 query as usual, and stores the answer in the backend.
 .P
 This module interacts with the \fBserve\-expired\-*\fR options and will reply
-with expired data if unbound is configured for that.  Currently the use
+with expired data if Unbound is configured for that.  Currently the use
 of \fBserve\-expired\-client\-timeout:\fR and
 \fBserve\-expired\-reply\-ttl:\fR is not consistent for data originating from
 the external cache as these will result in a reply with 0 TTL without trying to
@@ -2346,7 +2402,7 @@ This option defaults to "default".
 .P
 The following
 .B cachedb
-otions are specific to the redis backend.
+options are specific to the redis backend.
 .TP
 .B redis-server-host: \fI<server address or name>\fR
 The IP (either v6 or v4) address or domain name of the Redis server.
@@ -2367,16 +2423,17 @@ re-establish a new connection later.
 This option defaults to 100 milliseconds.
 .TP
 .B redis-expire-records: \fI<yes or no>
-If Redis record expiration is enabled.  If yes, unbound sets timeout for Redis
+If Redis record expiration is enabled.  If yes, Unbound sets timeout for Redis
 records so that Redis can evict keys that have expired automatically.  If
-unbound is configured with \fBserve-expired\fR and \fBserve-expired-ttl\fR is 0,
+Unbound is configured with \fBserve-expired\fR and \fBserve-expired-ttl\fR is 0,
 this option is internally reverted to "no".  Redis SETEX support is required
 for this option (Redis >= 2.0.0).
 This option defaults to no.
 .SS DNSTAP Logging Options
-DNSTAP support, when compiled in, is enabled in the \fBdnstap:\fR section.
+DNSTAP support, when compiled in by using \fB\-\-enable\-dnstap\fR, is enabled
+in the \fBdnstap:\fR section.
 This starts an extra thread (when compiled with threading) that writes
-the log information to the destination.  If unbound is compiled without
+the log information to the destination.  If Unbound is compiled without
 threading it does not spawn a thread, but connects per-process to the
 destination.
 .TP
@@ -2434,19 +2491,19 @@ Default is "".
 .TP
 .B dnstap-log-resolver-query-messages: \fI<yes or no>
 Enable to log resolver query messages.  Default is no.
-These are messages from unbound to upstream servers.
+These are messages from Unbound to upstream servers.
 .TP
 .B dnstap-log-resolver-response-messages: \fI<yes or no>
 Enable to log resolver response messages.  Default is no.
-These are replies from upstream servers to unbound.
+These are replies from upstream servers to Unbound.
 .TP
 .B dnstap-log-client-query-messages: \fI<yes or no>
 Enable to log client query messages.  Default is no.
-These are client queries to unbound.
+These are client queries to Unbound.
 .TP
 .B dnstap-log-client-response-messages: \fI<yes or no>
 Enable to log client response messages.  Default is no.
-These are responses from unbound to clients.
+These are responses from Unbound to clients.
 .TP
 .B dnstap-log-forwarder-query-messages: \fI<yes or no>
 Enable to log forwarder query messages.  Default is no.
@@ -2461,10 +2518,49 @@ with a different name. RPZ clauses are applied in order of configuration. The
 \fBrespip\fR module needs to be added to the \fBmodule-config\fR, e.g.:
 \fBmodule-config: "respip validator iterator"\fR.
 .P
-Only the QNAME and Response IP Address triggers are supported. The supported RPZ
-actions are: NXDOMAIN, NODATA, PASSTHRU, DROP and Local Data. RPZ QNAME triggers
-are applied after
-\fBlocal-zones\fR and before \fBauth-zones\fR.
+QNAME, Response IP Address, nsdname, nsip and clientip triggers are supported.
+Supported actions are: NXDOMAIN, NODATA, PASSTHRU, DROP, Local Data, tcp\-only
+and drop.  RPZ QNAME triggers are applied after \fBlocal\-zones\fR and
+before \fBauth\-zones\fR.
+.P
+The rpz zone is formatted with a SOA start record as usual.  The items in
+the zone are entries, that specify what to act on (the trigger) and what to
+do (the action).  The trigger to act on is recorded in the name, the action
+to do is recorded as the resource record.  The names all end in the zone
+name, so you could type the trigger names without a trailing dot in the
+zonefile.
+.P
+An example RPZ record, that answers example.com with NXDOMAIN
+.nf
+       example.com CNAME .
+.fi
+.P
+The triggers are encoded in the name on the left
+.nf
+       name                          query name
+       netblock.rpz-client-ip        client IP address
+       netblock.rpz-ip               response IP address in the answer
+       name.rpz-nsdname              nameserver name
+       netblock.rpz-nsip             nameserver IP address
+.fi
+The netblock is written as <netblocklen>.<ip address in reverse>.
+For IPv6 use 'zz' for '::'.  Specify individual addresses with scope length
+of 32 or 128.  For example, 24.10.100.51.198.rpz-ip is 198.51.100.10/24 and
+32.10.zz.db8.2001.rpz-ip is 2001:db8:0:0:0:0:0:10/32.
+.P
+The actions are specified with the record on the right
+.nf
+       CNAME .                      nxdomain reply
+       CNAME *.                     nodata reply
+       CNAME rpz-passthru.          do nothing, allow to continue
+       CNAME rpz-drop.              the query is dropped
+       CNAME rpz-tcp-only.          answer over TCP
+       A 192.0.2.1                  answer with this IP address
+.fi
+Other records like AAAA, TXT and other CNAMEs (not rpz-..) can also be used to
+answer queries with that content.
+.P
+The RPZ zones can be configured in the config file with these settings in the \fBrpz:\fR block.
 .TP
 .B name: \fI<zone name>
 Name of the authority zone.
@@ -2506,7 +2602,7 @@ allowed notify by default.
 .TP
 .B zonefile: \fI<filename>
 The filename where the zone is stored.  If not given then no zonefile is used.
-If the file does not exist or is empty, unbound will attempt to fetch zone
+If the file does not exist or is empty, Unbound will attempt to fetch zone
 data (eg. from the primary servers).
 .TP
 .B rpz\-action\-override: \fI<action>
@@ -2523,6 +2619,17 @@ Log all applied RPZ actions for this RPZ zone. Default is no.
 .B rpz\-log\-name: \fI<name>
 Specify a string to be part of the log line, for easy referencing.
 .TP
+.B rpz\-signal\-nxdomain\-ra: \fI<yes or no>
+Signal when a query is blocked by the RPZ with NXDOMAIN with an unset RA flag.
+This allows certain clients, like dnsmasq, to infer that the domain is
+externally blocked. Default is no.
+.TP
+.B for\-downstream: \fI<yes or no>
+If enabled the zone is authoritatively answered for and queries for the RPZ
+zone information are answered to downstream clients. This is useful for
+monitoring scripts, that can then access the SOA information to check if
+the rpz information is up to date. Default is no.
+.TP
 .B tags: \fI<list of tags>
 Limit the policies from this RPZ clause to clients with a matching tag. Tags
 need to be defined in \fBdefine\-tag\fR and can be assigned to client addresses
@@ -2563,7 +2670,7 @@ server:
 .SH "FILES"
 .TP
 .I @UNBOUND_RUN_DIR@
-default unbound working directory.
+default Unbound working directory.
 .TP
 .I @UNBOUND_CHROOT_DIR@
 default
@@ -2571,10 +2678,10 @@ default
 location.
 .TP
 .I @ub_conf_file@
-unbound configuration file.
+Unbound configuration file.
 .TP
 .I unbound.log
-unbound log file. default is to log to
+Unbound log file. default is to log to
 \fIsyslog\fR(3).
 .SH "SEE ALSO"
 \fIunbound\fR(8),
index 823e092..7222dbc 100644 (file)
@@ -279,10 +279,10 @@ TYPEDEF_HIDES_STRUCT   = NO
 # For small to medium size projects (<1000 input files) the default value is
 # probably good enough. For larger projects a too small cache size can cause
 # doxygen to be busy swapping symbols to and from disk most of the time
-# causing a significant performance penality.
+# causing a significant performance penalty.
 # If the system has enough physical memory increasing the cache will improve the
 # performance by keeping more symbols in memory. Note that the value works on
-# a logarithmic scale so increasing the size by one will rougly double the
+# a logarithmic scale so increasing the size by one will roughly double the
 # memory usage. The cache size is given by this formula:
 # 2^(16+SYMBOL_CACHE_SIZE). The valid range is 0..9, the default is 0,
 # corresponding to a cache size of 2^16 = 65536 symbols
@@ -779,7 +779,7 @@ ALPHABETICAL_INDEX     = YES
 # the COLS_IN_ALPHA_INDEX tag can be used to specify the number of columns
 # in which this list will be split (can be a number in the range [1..20])
 
-COLS_IN_ALPHA_INDEX    = 5
+#COLS_IN_ALPHA_INDEX    = 5
 
 # In case all classes in a project start with a common prefix, all
 # classes will be put under the same header in the alphabetical index.
index ade40c6..81f0bf3 100644 (file)
@@ -497,7 +497,7 @@ eval_response(struct module_qstate *qstate, int id, struct subnet_qstate *sq)
        if (!s_in->subnet_validdata) {
                /* The authority indicated no support for edns subnet. As a
                 * consequence the answer ended up in the regular cache. It
-                * is still usefull to put it in the edns subnet cache for
+                * is still useful to put it in the edns subnet cache for
                 * when a client explicitly asks for subnet specific answer. */
                verbose(VERB_QUERY, "subnetcache: Authority indicates no support");
                if(!sq->started_no_cache_store) {
index e42af6f..577f711 100644 (file)
@@ -37,7 +37,7 @@
  * \file
  *
  * This file contains a module that facilitates opportunistic IPsec. It does so
- * by also quering for the IPSECKEY for A/AAAA queries and calling a
+ * by also querying for the IPSECKEY for A/AAAA queries and calling a
  * configurable hook (eg. signaling an IKE daemon) before replying.
  */
 
index 9a672b0..80148e8 100644 (file)
@@ -73,8 +73,10 @@ struct delegpt* delegpt_copy(struct delegpt* dp, struct regional* region)
        copy->bogus = dp->bogus;
        copy->has_parent_side_NS = dp->has_parent_side_NS;
        copy->ssl_upstream = dp->ssl_upstream;
+       copy->tcp_upstream = dp->tcp_upstream;
        for(ns = dp->nslist; ns; ns = ns->next) {
-               if(!delegpt_add_ns(copy, region, ns->name, ns->lame))
+               if(!delegpt_add_ns(copy, region, ns->name, ns->lame,
+                       ns->tls_auth_name, ns->port))
                        return NULL;
                copy->nslist->resolved = ns->resolved;
                copy->nslist->got4 = ns->got4;
@@ -83,8 +85,8 @@ struct delegpt* delegpt_copy(struct delegpt* dp, struct regional* region)
                copy->nslist->done_pside6 = ns->done_pside6;
        }
        for(a = dp->target_list; a; a = a->next_target) {
-               if(!delegpt_add_addr(copy, region, &a->addr, a->addrlen, 
-                       a->bogus, a->lame, a->tls_auth_name, NULL))
+               if(!delegpt_add_addr(copy, region, &a->addr, a->addrlen,
+                       a->bogus, a->lame, a->tls_auth_name, -1, NULL))
                        return NULL;
        }
        return copy;
@@ -101,7 +103,7 @@ delegpt_set_name(struct delegpt* dp, struct regional* region, uint8_t* name)
 
 int 
 delegpt_add_ns(struct delegpt* dp, struct regional* region, uint8_t* name,
-       uint8_t lame)
+       uint8_t lame, char* tls_auth_name, int port)
 {
        struct delegpt_ns* ns;
        size_t len;
@@ -125,6 +127,14 @@ delegpt_add_ns(struct delegpt* dp, struct regional* region, uint8_t* name,
        ns->lame = lame;
        ns->done_pside4 = 0;
        ns->done_pside6 = 0;
+       ns->port = port;
+       if(tls_auth_name) {
+               ns->tls_auth_name = regional_strdup(region, tls_auth_name);
+               if(!ns->tls_auth_name)
+                       return 0;
+       } else {
+               ns->tls_auth_name = NULL;
+       }
        return ns->name != 0;
 }
 
@@ -158,9 +168,9 @@ delegpt_find_addr(struct delegpt* dp, struct sockaddr_storage* addr,
        return NULL;
 }
 
-int 
-delegpt_add_target(struct delegpt* dp, struct regional* region, 
-       uint8_t* name, size_t namelen, struct sockaddr_storage* addr, 
+int
+delegpt_add_target(struct delegpt* dp, struct regional* region,
+       uint8_t* name, size_t namelen, struct sockaddr_storage* addr,
        socklen_t addrlen, uint8_t bogus, uint8_t lame, int* additions)
 {
        struct delegpt_ns* ns = delegpt_find_ns(dp, name, namelen);
@@ -176,17 +186,22 @@ delegpt_add_target(struct delegpt* dp, struct regional* region,
                if(ns->got4 && ns->got6)
                        ns->resolved = 1;
        }
-       return delegpt_add_addr(dp, region, addr, addrlen, bogus, lame, NULL,
-               additions);
+       log_assert(ns->port>0);
+       return delegpt_add_addr(dp, region, addr, addrlen, bogus, lame,
+               ns->tls_auth_name, ns->port, additions);
 }
 
-int 
-delegpt_add_addr(struct delegpt* dp, struct regional* region, 
-       struct sockaddr_storage* addr, socklen_t addrlen, uint8_t bogus, 
-       uint8_t lame, char* tls_auth_name, int* additions)
+int
+delegpt_add_addr(struct delegpt* dp, struct regional* region,
+       struct sockaddr_storage* addr, socklen_t addrlen, uint8_t bogus,
+       uint8_t lame, char* tls_auth_name, int port, int* additions)
 {
        struct delegpt_addr* a;
        log_assert(!dp->dp_type_mlc);
+       if(port != -1) {
+               log_assert(port>0);
+               sockaddr_store_port(addr, addrlen, port);
+       }
        /* check for duplicates */
        if((a = delegpt_find_addr(dp, addr, addrlen))) {
                if(bogus)
@@ -411,7 +426,8 @@ delegpt_rrset_add_ns(struct delegpt* dp, struct regional* region,
                        (size_t)sldns_read_uint16(nsdata->rr_data[i]))
                        continue; /* bad format */
                /* add rdata of NS (= wirefmt dname), skip rdatalen bytes */
-               if(!delegpt_add_ns(dp, region, nsdata->rr_data[i]+2, lame))
+               if(!delegpt_add_ns(dp, region, nsdata->rr_data[i]+2, lame,
+                       NULL, UNBOUND_DNS_PORT))
                        return 0;
        }
        return 1;
@@ -428,7 +444,6 @@ delegpt_add_rrset_A(struct delegpt* dp, struct regional* region,
        log_assert(!dp->dp_type_mlc);
         memset(&sa, 0, len);
         sa.sin_family = AF_INET;
-        sa.sin_port = (in_port_t)htons(UNBOUND_DNS_PORT);
         for(i=0; i<d->count; i++) {
                 if(d->rr_len[i] != 2 + INET_SIZE)
                         continue;
@@ -452,7 +467,6 @@ delegpt_add_rrset_AAAA(struct delegpt* dp, struct regional* region,
        log_assert(!dp->dp_type_mlc);
         memset(&sa, 0, len);
         sa.sin6_family = AF_INET6;
-        sa.sin6_port = (in_port_t)htons(UNBOUND_DNS_PORT);
         for(i=0; i<d->count; i++) {
                 if(d->rr_len[i] != 2 + INET6_SIZE) /* rdatalen + len of IP6 */
                         continue;
@@ -554,6 +568,7 @@ void delegpt_free_mlc(struct delegpt* dp)
        while(n) {
                nn = n->next;
                free(n->name);
+               free(n->tls_auth_name);
                free(n);
                n = nn;
        }
@@ -576,7 +591,8 @@ int delegpt_set_name_mlc(struct delegpt* dp, uint8_t* name)
        return (dp->name != NULL);
 }
 
-int delegpt_add_ns_mlc(struct delegpt* dp, uint8_t* name, uint8_t lame)
+int delegpt_add_ns_mlc(struct delegpt* dp, uint8_t* name, uint8_t lame,
+       char* tls_auth_name, int port)
 {
        struct delegpt_ns* ns;
        size_t len;
@@ -603,14 +619,30 @@ int delegpt_add_ns_mlc(struct delegpt* dp, uint8_t* name, uint8_t lame)
        ns->lame = (uint8_t)lame;
        ns->done_pside4 = 0;
        ns->done_pside6 = 0;
+       ns->port = port;
+       if(tls_auth_name) {
+               ns->tls_auth_name = strdup(tls_auth_name);
+               if(!ns->tls_auth_name) {
+                       free(ns->name);
+                       free(ns);
+                       return 0;
+               }
+       } else {
+               ns->tls_auth_name = NULL;
+       }
        return 1;
 }
 
 int delegpt_add_addr_mlc(struct delegpt* dp, struct sockaddr_storage* addr,
-       socklen_t addrlen, uint8_t bogus, uint8_t lame, char* tls_auth_name)
+       socklen_t addrlen, uint8_t bogus, uint8_t lame, char* tls_auth_name,
+       int port)
 {
        struct delegpt_addr* a;
        log_assert(dp->dp_type_mlc);
+       if(port != -1) {
+               log_assert(port>0);
+               sockaddr_store_port(addr, addrlen, port);
+       }
        /* check for duplicates */
        if((a = delegpt_find_addr(dp, addr, addrlen))) {
                if(bogus)
@@ -663,7 +695,9 @@ int delegpt_add_target_mlc(struct delegpt* dp, uint8_t* name, size_t namelen,
                if(ns->got4 && ns->got6)
                        ns->resolved = 1;
        }
-       return delegpt_add_addr_mlc(dp, addr, addrlen, bogus, lame, NULL);
+       log_assert(ns->port>0);
+       return delegpt_add_addr_mlc(dp, addr, addrlen, bogus, lame,
+               ns->tls_auth_name, ns->port);
 }
 
 size_t delegpt_get_mem(struct delegpt* dp)
index 138eb6e..17db15a 100644 (file)
@@ -83,6 +83,8 @@ struct delegpt {
        uint8_t dp_type_mlc;
        /** use SSL for upstream query */
        uint8_t ssl_upstream;
+       /** use TCP for upstream query */
+       uint8_t tcp_upstream;
        /** delegpt from authoritative zone that is locally hosted */
        uint8_t auth_dp;
        /*** no cache */
@@ -124,6 +126,11 @@ struct delegpt_ns {
         * Also enabled if a parent-side cache entry exists, or a parent-side
         * negative-cache entry exists. */
        uint8_t done_pside6;
+       /** the TLS authentication name, (if not NULL) to use. */
+       char* tls_auth_name;
+       /** the port to use; it should mosty be the default 53 but configured
+        *  upstreams can provide nondefault ports. */
+       int port;
 };
 
 /**
@@ -189,10 +196,12 @@ int delegpt_set_name(struct delegpt* dp, struct regional* regional,
  * @param regional: where to allocate the info.
  * @param name: domain name in wire format.
  * @param lame: name is lame, disprefer it.
+ * @param tls_auth_name: TLS authentication name (or NULL).
+ * @param port: port to use for resolved addresses.
  * @return false on error.
  */
-int delegpt_add_ns(struct delegpt* dp, struct regional* regional, 
-       uint8_t* name, uint8_t lame);
+int delegpt_add_ns(struct delegpt* dp, struct regional* regional,
+       uint8_t* name, uint8_t lame, char* tls_auth_name, int port);
 
 /**
  * Add NS rrset; calls add_ns repeatedly.
@@ -269,12 +278,14 @@ int delegpt_add_rrset(struct delegpt* dp, struct regional* regional,
  * @param bogus: if address is bogus.
  * @param lame: if address is lame.
  * @param tls_auth_name: TLS authentication name (or NULL).
+ * @param port: the port to use; if -1 the port is taken from addr.
  * @param additions: will be set to 1 if a new address is added
  * @return false on error.
  */
-int delegpt_add_addr(struct delegpt* dp, struct regional* regional, 
+int delegpt_add_addr(struct delegpt* dp, struct regional* regional,
        struct sockaddr_storage* addr, socklen_t addrlen,
-       uint8_t bogus, uint8_t lame, char* tls_auth_name, int* additions);
+       uint8_t bogus, uint8_t lame, char* tls_auth_name, int port,
+       int* additions);
 
 /** 
  * Find NS record in name list of delegation point.
@@ -402,22 +413,27 @@ int delegpt_set_name_mlc(struct delegpt* dp, uint8_t* name);
  * @param dp: must have been created with delegpt_create_mlc. 
  * @param name: the name to add.
  * @param lame: the name is lame, disprefer.
+ * @param tls_auth_name: TLS authentication name (or NULL).
+ * @param port: port to use for resolved addresses.
  * @return false on error.
  */
-int delegpt_add_ns_mlc(struct delegpt* dp, uint8_t* name, uint8_t lame);
+int delegpt_add_ns_mlc(struct delegpt* dp, uint8_t* name, uint8_t lame,
+       char* tls_auth_name, int port);
 
 /**
  * add an address to a malloced delegation point.
- * @param dp: must have been created with delegpt_create_mlc. 
+ * @param dp: must have been created with delegpt_create_mlc.
  * @param addr: the address.
  * @param addrlen: the length of addr.
  * @param bogus: if address is bogus.
  * @param lame: if address is lame.
  * @param tls_auth_name: TLS authentication name (or NULL).
+ * @param port: the port to use; if -1 the port is taken from addr.
  * @return false on error.
  */
 int delegpt_add_addr_mlc(struct delegpt* dp, struct sockaddr_storage* addr,
-       socklen_t addrlen, uint8_t bogus, uint8_t lame, char* tls_auth_name);
+       socklen_t addrlen, uint8_t bogus, uint8_t lame, char* tls_auth_name,
+       int port);
 
 /**
  * Add target address to the delegation point.
index ea3d70e..1513729 100644 (file)
@@ -200,21 +200,27 @@ read_fwds_name(struct config_stub* s)
 }
 
 /** set fwd host names */
-static int 
+static int
 read_fwds_host(struct config_stub* s, struct delegpt* dp)
 {
        struct config_strlist* p;
        uint8_t* dname;
-       size_t dname_len;
+       char* tls_auth_name;
+       int port;
        for(p = s->hosts; p; p = p->next) {
                log_assert(p->str);
-               dname = sldns_str2wire_dname(p->str, &dname_len);
+               dname = authextstrtodname(p->str, &port, &tls_auth_name);
                if(!dname) {
                        log_err("cannot parse forward %s server name: '%s'", 
                                s->name, p->str);
                        return 0;
                }
-               if(!delegpt_add_ns_mlc(dp, dname, 0)) {
+#if ! defined(HAVE_SSL_SET1_HOST) && ! defined(HAVE_X509_VERIFY_PARAM_SET1_HOST)
+               if(tls_auth_name)
+                       log_err("no name verification functionality in "
+                               "ssl library, ignored name for %s", p->str);
+#endif
+               if(!delegpt_add_ns_mlc(dp, dname, 0, tls_auth_name, port)) {
                        free(dname);
                        log_err("out of memory");
                        return 0;
@@ -245,7 +251,7 @@ read_fwds_addr(struct config_stub* s, struct delegpt* dp)
                                "ssl library, ignored name for %s", p->str);
 #endif
                if(!delegpt_add_addr_mlc(dp, &addr, addrlen, 0, 0,
-                       tls_auth_name)) {
+                       tls_auth_name, -1)) {
                        log_err("out of memory");
                        return 0;
                }
@@ -276,6 +282,8 @@ read_forwards(struct iter_forwards* fwd, struct config_file* cfg)
                dp->no_cache = s->no_cache;
                /* use SSL for queries to this forwarder */
                dp->ssl_upstream = (uint8_t)s->ssl_upstream;
+               /* use TCP for queries to this forwarder */
+               dp->tcp_upstream = (uint8_t)s->tcp_upstream;
                verbose(VERB_QUERY, "Forward zone server list:");
                delegpt_log(VERB_QUERY, dp);
                if(!forwards_insert(fwd, LDNS_RR_CLASS_IN, dp))
index 60e5181..9b1a200 100644 (file)
@@ -99,7 +99,7 @@ ah(struct delegpt* dp, const char* sv, const char* ip)
                log_err("could not parse %s", sv);
                return 0;
        }
-       if(!delegpt_add_ns_mlc(dp, dname, 0) ||
+       if(!delegpt_add_ns_mlc(dp, dname, 0, NULL, UNBOUND_DNS_PORT) ||
           !extstrtoaddr(ip, &addr, &addrlen) ||
           !delegpt_add_target_mlc(dp, dname, dname_len,
                &addr, addrlen, 0, 0)) {
@@ -213,21 +213,27 @@ read_stubs_name(struct config_stub* s)
 }
 
 /** set stub host names */
-static int 
+static int
 read_stubs_host(struct config_stub* s, struct delegpt* dp)
 {
        struct config_strlist* p;
-       size_t dname_len;
        uint8_t* dname;
+       char* tls_auth_name;
+       int port;
        for(p = s->hosts; p; p = p->next) {
                log_assert(p->str);
-               dname = sldns_str2wire_dname(p->str, &dname_len);
+               dname = authextstrtodname(p->str, &port, &tls_auth_name);
                if(!dname) {
                        log_err("cannot parse stub %s nameserver name: '%s'", 
                                s->name, p->str);
                        return 0;
                }
-               if(!delegpt_add_ns_mlc(dp, dname, 0)) {
+#if ! defined(HAVE_SSL_SET1_HOST) && ! defined(HAVE_X509_VERIFY_PARAM_SET1_HOST)
+               if(tls_auth_name)
+                       log_err("no name verification functionality in "
+                               "ssl library, ignored name for %s", p->str);
+#endif
+               if(!delegpt_add_ns_mlc(dp, dname, 0, tls_auth_name, port)) {
                        free(dname);
                        log_err("out of memory");
                        return 0;
@@ -258,7 +264,7 @@ read_stubs_addr(struct config_stub* s, struct delegpt* dp)
                                "ssl library, ignored name for %s", p->str);
 #endif
                if(!delegpt_add_addr_mlc(dp, &addr, addrlen, 0, 0,
-                       auth_name)) {
+                       auth_name, -1)) {
                        log_err("out of memory");
                        return 0;
                }
@@ -287,6 +293,8 @@ read_stubs(struct iter_hints* hints, struct config_file* cfg)
                dp->no_cache = s->no_cache;
                /* ssl_upstream */
                dp->ssl_upstream = (uint8_t)s->ssl_upstream;
+               /* tcp_upstream */
+               dp->tcp_upstream = (uint8_t)s->tcp_upstream;
                delegpt_log(VERB_QUERY, dp);
                if(!hints_insert(hints, LDNS_RR_CLASS_IN, dp, !s->isprime))
                        return 0;
@@ -336,7 +344,7 @@ read_root_hints(struct iter_hints* hints, char* fname)
                if(sldns_wirerr_get_type(rr, rr_len, dname_len)
                        == LDNS_RR_TYPE_NS) {
                        if(!delegpt_add_ns_mlc(dp, sldns_wirerr_get_rdata(rr,
-                               rr_len, dname_len), 0)) {
+                               rr_len, dname_len), 0, NULL, UNBOUND_DNS_PORT)) {
                                log_err("out of memory reading root hints");
                                goto stop_read;
                        }
@@ -395,10 +403,10 @@ read_root_hints(struct iter_hints* hints, char* fname)
                delegpt_free_mlc(dp);
                return 1;
        }
+       delegpt_log(VERB_QUERY, dp);
        if(!hints_insert(hints, c, dp, 0)) {
                return 0;
        }
-       delegpt_log(VERB_QUERY, dp);
        return 1;
 
 stop_read:
index 668f898..2482a1f 100644 (file)
@@ -4,22 +4,22 @@
  * Copyright (c) 2007, NLnet Labs. All rights reserved.
  *
  * This software is open source.
- * 
+ *
  * Redistribution and use in source and binary forms, with or without
  * modification, are permitted provided that the following conditions
  * are met:
- * 
+ *
  * Redistributions of source code must retain the above copyright notice,
  * this list of conditions and the following disclaimer.
- * 
+ *
  * Redistributions in binary form must reproduce the above copyright notice,
  * this list of conditions and the following disclaimer in the documentation
  * and/or other materials provided with the distribution.
- * 
+ *
  * Neither the name of the NLNET LABS nor the names of its contributors may
  * be used to endorse or promote products derived from this software without
  * specific prior written permission.
- * 
+ *
  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
  * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
  * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
@@ -37,7 +37,7 @@
  * \file
  *
  * This file contains functions to assist the iterator module.
- * Configuration options. Forward zones. 
+ * Configuration options. Forward zones.
  */
 #include "config.h"
 #include "iterator/iter_utils.h"
@@ -141,7 +141,7 @@ caps_white_apply_cfg(rbtree_type* ntree, struct config_file* cfg)
        return 1;
 }
 
-int 
+int
 iter_apply_cfg(struct iter_env* iter_env, struct config_file* cfg)
 {
        int i;
@@ -151,7 +151,7 @@ iter_apply_cfg(struct iter_env* iter_env, struct config_file* cfg)
        for(i=0; i<iter_env->max_dependency_depth+1; i++)
                verbose(VERB_QUERY, "target fetch policy for level %d is %d",
                        i, iter_env->target_fetch_policy[i]);
-       
+
        if(!iter_env->donotq)
                iter_env->donotq = donotq_create();
        if(!iter_env->donotq || !donotq_apply_cfg(iter_env->donotq, cfg)) {
@@ -176,6 +176,7 @@ iter_apply_cfg(struct iter_env* iter_env, struct config_file* cfg)
        }
        iter_env->supports_ipv6 = cfg->do_ip6;
        iter_env->supports_ipv4 = cfg->do_ip4;
+       iter_env->outbound_msg_retry = cfg->outbound_msg_retry;
        return 1;
 }
 
@@ -212,7 +213,7 @@ iter_apply_cfg(struct iter_env* iter_env, struct config_file* cfg)
  *             dnsseclame servers get penalty
  *     USEFUL_SERVER_TOP_TIMEOUT*3 ..
  *             recursion lame servers get penalty
- *     UNKNOWN_SERVER_NICENESS 
+ *     UNKNOWN_SERVER_NICENESS
  *             If no information is known about the server, this is
  *             returned. 376 msec or so.
  *     +BLACKLIST_PENALTY (of USEFUL_TOP_TIMEOUT*4) for dnssec failed IPs.
@@ -221,11 +222,11 @@ iter_apply_cfg(struct iter_env* iter_env, struct config_file* cfg)
  * is turned off (so we do not discard the reply).
  * When a final value is chosen that is recursionlame; RD bit is set on query.
  * Because of the numbers this means recursionlame also have dnssec lameness
- * checking turned off. 
+ * checking turned off.
  */
 static int
 iter_filter_unsuitable(struct iter_env* iter_env, struct module_env* env,
-       uint8_t* name, size_t namelen, uint16_t qtype, time_t now, 
+       uint8_t* name, size_t namelen, uint16_t qtype, time_t now,
        struct delegpt_addr* a)
 {
        int rtt, lame, reclame, dnsseclame;
@@ -243,8 +244,8 @@ iter_filter_unsuitable(struct iter_env* iter_env, struct module_env* env,
                return -1; /* there is no ip4 available */
        }
        /* check lameness - need zone , class info */
-       if(infra_get_lame_rtt(env->infra_cache, &a->addr, a->addrlen, 
-               name, namelen, qtype, &lame, &dnsseclame, &reclame, 
+       if(infra_get_lame_rtt(env->infra_cache, &a->addr, a->addrlen,
+               name, namelen, qtype, &lame, &dnsseclame, &reclame,
                &rtt, now)) {
                log_addr(VERB_ALGO, "servselect", &a->addr, a->addrlen);
                verbose(VERB_ALGO, "   rtt=%d%s%s%s%s", rtt,
@@ -282,7 +283,7 @@ iter_filter_unsuitable(struct iter_env* iter_env, struct module_env* env,
 /** lookup RTT information, and also store fastest rtt (if any) */
 static int
 iter_fill_rtt(struct iter_env* iter_env, struct module_env* env,
-       uint8_t* name, size_t namelen, uint16_t qtype, time_t now, 
+       uint8_t* name, size_t namelen, uint16_t qtype, time_t now,
        struct delegpt* dp, int* best_rtt, struct sock_list* blacklist,
        size_t* num_suitable_results)
 {
@@ -293,7 +294,7 @@ iter_fill_rtt(struct iter_env* iter_env, struct module_env* env,
        if(dp->bogus)
                return 0; /* NS bogus, all bogus, nothing found */
        for(a=dp->result_list; a; a = a->next_result) {
-               a->sel_rtt = iter_filter_unsuitable(iter_env, env, 
+               a->sel_rtt = iter_filter_unsuitable(iter_env, env,
                        name, namelen, qtype, now, a);
                if(a->sel_rtt != -1) {
                        if(sock_list_find(blacklist, &a->addr, a->addrlen))
@@ -329,7 +330,7 @@ nth_rtt(struct delegpt_addr* result_list, size_t num_results, size_t n)
        int rtt_band;
        size_t i;
        int* rtt_list, *rtt_index;
-       
+
        if(num_results < 1 || n >= num_results) {
                return -1;
        }
@@ -361,8 +362,8 @@ nth_rtt(struct delegpt_addr* result_list, size_t num_results, size_t n)
  * returns number of best targets (or 0, no suitable targets) */
 static int
 iter_filter_order(struct iter_env* iter_env, struct module_env* env,
-       uint8_t* name, size_t namelen, uint16_t qtype, time_t now, 
-       struct delegpt* dp, int* selected_rtt, int open_target, 
+       uint8_t* name, size_t namelen, uint16_t qtype, time_t now,
+       struct delegpt* dp, int* selected_rtt, int open_target,
        struct sock_list* blacklist, time_t prefetch)
 {
        int got_num = 0, low_rtt = 0, swap_to_front, rtt_band = RTT_BAND, nth;
@@ -370,9 +371,9 @@ iter_filter_order(struct iter_env* iter_env, struct module_env* env,
        struct delegpt_addr* a, *n, *prev=NULL;
 
        /* fillup sel_rtt and find best rtt in the bunch */
-       got_num = iter_fill_rtt(iter_env, env, name, namelen, qtype, now, dp, 
+       got_num = iter_fill_rtt(iter_env, env, name, namelen, qtype, now, dp,
                &low_rtt, blacklist, &num_results);
-       if(got_num == 0) 
+       if(got_num == 0)
                return 0;
        if(low_rtt >= USEFUL_SERVER_TOP_TIMEOUT &&
                (delegpt_count_missing_targets(dp) > 0 || open_target > 0)) {
@@ -548,9 +549,9 @@ iter_filter_order(struct iter_env* iter_env, struct module_env* env,
        return got_num;
 }
 
-struct delegpt_addr* 
-iter_server_selection(struct iter_env* iter_env, 
-       struct module_env* env, struct delegpt* dp, 
+struct delegpt_addr*
+iter_server_selection(struct iter_env* iter_env,
+       struct module_env* env, struct delegpt* dp,
        uint8_t* name, size_t namelen, uint16_t qtype, int* dnssec_lame,
        int* chase_to_rd, int open_target, struct sock_list* blacklist,
        time_t prefetch)
@@ -592,7 +593,7 @@ iter_server_selection(struct iter_env* iter_env,
 
        if(num == 1) {
                a = dp->result_list;
-               if(++a->attempts < OUTBOUND_MSG_RETRY)
+               if(++a->attempts < iter_env->outbound_msg_retry)
                        return a;
                dp->result_list = a->next_result;
                return a;
@@ -602,7 +603,7 @@ iter_server_selection(struct iter_env* iter_env,
        log_assert(num > 1);
        /* grab secure random number, to pick unexpected server.
         * also we need it to be threadsafe. */
-       sel = ub_random_max(env->rnd, num); 
+       sel = ub_random_max(env->rnd, num);
        a = dp->result_list;
        prev = NULL;
        while(sel > 0 && a) {
@@ -612,7 +613,7 @@ iter_server_selection(struct iter_env* iter_env,
        }
        if(!a)  /* robustness */
                return NULL;
-       if(++a->attempts < OUTBOUND_MSG_RETRY)
+       if(++a->attempts < iter_env->outbound_msg_retry)
                return a;
        /* remove it from the delegation point result list */
        if(prev)
@@ -621,8 +622,8 @@ iter_server_selection(struct iter_env* iter_env,
        return a;
 }
 
-struct dns_msg* 
-dns_alloc_msg(sldns_buffer* pkt, struct msg_parse* msg, 
+struct dns_msg*
+dns_alloc_msg(sldns_buffer* pkt, struct msg_parse* msg,
        struct regional* region)
 {
        struct dns_msg* m = (struct dns_msg*)regional_alloc(region,
@@ -637,7 +638,7 @@ dns_alloc_msg(sldns_buffer* pkt, struct msg_parse* msg,
        return m;
 }
 
-struct dns_msg* 
+struct dns_msg*
 dns_copy_msg(struct dns_msg* from, struct regional* region)
 {
        struct dns_msg* m = (struct dns_msg*)regional_alloc(region,
@@ -653,7 +654,7 @@ dns_copy_msg(struct dns_msg* from, struct regional* region)
        return m;
 }
 
-void 
+void
 iter_dns_store(struct module_env* env, struct query_info* msgqinf,
        struct reply_info* msgrep, int is_referral, time_t leeway, int pside,
        struct regional* region, uint16_t flags)
@@ -663,7 +664,7 @@ iter_dns_store(struct module_env* env, struct query_info* msgqinf,
                log_err("out of memory: cannot store data in cache");
 }
 
-int 
+int
 iter_ns_probability(struct ub_randstate* rnd, int n, int m)
 {
        int sel;
@@ -671,7 +672,7 @@ iter_ns_probability(struct ub_randstate* rnd, int n, int m)
                return 1;
        /* we do not need secure random numbers here, but
         * we do need it to be threadsafe, so we use this */
-       sel = ub_random_max(rnd, m); 
+       sel = ub_random_max(rnd, m);
        return (sel < n);
 }
 
@@ -688,12 +689,12 @@ causes_cycle(struct module_qstate* qstate, uint8_t* name, size_t namelen,
        qinf.local_alias = NULL;
        fptr_ok(fptr_whitelist_modenv_detect_cycle(
                qstate->env->detect_cycle));
-       return (*qstate->env->detect_cycle)(qstate, &qinf, 
+       return (*qstate->env->detect_cycle)(qstate, &qinf,
                (uint16_t)(BIT_RD|BIT_CD), qstate->is_priming,
                qstate->is_valrec);
 }
 
-void 
+void
 iter_mark_cycle_targets(struct module_qstate* qstate, struct delegpt* dp)
 {
        struct delegpt_ns* ns;
@@ -701,21 +702,21 @@ iter_mark_cycle_targets(struct module_qstate* qstate, struct delegpt* dp)
                if(ns->resolved)
                        continue;
                /* see if this ns as target causes dependency cycle */
-               if(causes_cycle(qstate, ns->name, ns->namelen, 
+               if(causes_cycle(qstate, ns->name, ns->namelen,
                        LDNS_RR_TYPE_AAAA, qstate->qinfo.qclass) ||
-                  causes_cycle(qstate, ns->name, ns->namelen, 
+                  causes_cycle(qstate, ns->name, ns->namelen,
                        LDNS_RR_TYPE_A, qstate->qinfo.qclass)) {
                        log_nametypeclass(VERB_QUERY, "skipping target due "
                                "to dependency cycle (harden-glue: no may "
-                               "fix some of the cycles)", 
-                               ns->name, LDNS_RR_TYPE_A, 
+                               "fix some of the cycles)",
+                               ns->name, LDNS_RR_TYPE_A,
                                qstate->qinfo.qclass);
                        ns->resolved = 1;
                }
        }
 }
 
-void 
+void
 iter_mark_pside_cycle_targets(struct module_qstate* qstate, struct delegpt* dp)
 {
        struct delegpt_ns* ns;
@@ -723,14 +724,14 @@ iter_mark_pside_cycle_targets(struct module_qstate* qstate, struct delegpt* dp)
                if(ns->done_pside4 && ns->done_pside6)
                        continue;
                /* see if this ns as target causes dependency cycle */
-               if(causes_cycle(qstate, ns->name, ns->namelen, 
+               if(causes_cycle(qstate, ns->name, ns->namelen,
                        LDNS_RR_TYPE_A, qstate->qinfo.qclass)) {
                        log_nametypeclass(VERB_QUERY, "skipping target due "
                                "to dependency cycle", ns->name,
                                LDNS_RR_TYPE_A, qstate->qinfo.qclass);
                        ns->done_pside4 = 1;
                }
-               if(causes_cycle(qstate, ns->name, ns->namelen, 
+               if(causes_cycle(qstate, ns->name, ns->namelen,
                        LDNS_RR_TYPE_AAAA, qstate->qinfo.qclass)) {
                        log_nametypeclass(VERB_QUERY, "skipping target due "
                                "to dependency cycle", ns->name,
@@ -740,8 +741,8 @@ iter_mark_pside_cycle_targets(struct module_qstate* qstate, struct delegpt* dp)
        }
 }
 
-int 
-iter_dp_is_useless(struct query_info* qinfo, uint16_t qflags, 
+int
+iter_dp_is_useless(struct query_info* qinfo, uint16_t qflags,
        struct delegpt* dp)
 {
        struct delegpt_ns* ns;
@@ -760,14 +761,14 @@ iter_dp_is_useless(struct query_info* qinfo, uint16_t qflags,
        /* either available or unused targets */
        if(dp->usable_list || dp->result_list)
                return 0;
-       
+
        /* see if query is for one of the nameservers, which is glue */
        if( (qinfo->qtype == LDNS_RR_TYPE_A ||
                qinfo->qtype == LDNS_RR_TYPE_AAAA) &&
                dname_subdomain_c(qinfo->qname, dp->name) &&
                delegpt_find_ns(dp, qinfo->qname, qinfo->qname_len))
                return 1;
-       
+
        for(ns = dp->nslist; ns; ns = ns->next) {
                if(ns->resolved) /* skip failed targets */
                        continue;
@@ -785,7 +786,7 @@ iter_qname_indicates_dnssec(struct module_env* env, struct query_info *qinfo)
                return 0;
        /* a trust anchor exists above the name? */
        if((a=anchors_lookup(env->anchors, qinfo->qname, qinfo->qname_len,
-               qinfo->qclass))) { 
+               qinfo->qclass))) {
                if(a->numDS == 0 && a->numDNSKEY == 0) {
                        /* insecure trust point */
                        lock_basic_unlock(&a->lock);
@@ -798,7 +799,7 @@ iter_qname_indicates_dnssec(struct module_env* env, struct query_info *qinfo)
        return 0;
 }
 
-int 
+int
 iter_indicates_dnssec(struct module_env* env, struct delegpt* dp,
         struct dns_msg* msg, uint16_t dclass)
 {
@@ -842,7 +843,7 @@ iter_indicates_dnssec(struct module_env* env, struct delegpt* dp,
        return 0;
 }
 
-int 
+int
 iter_msg_has_dnssec(struct dns_msg* msg)
 {
        size_t i;
@@ -875,7 +876,7 @@ int iter_msg_from_zone(struct dns_msg* msg, struct delegpt* dp,
                 * and referral to example.com. NS ... , then origin zone
                 * is .com. For a referral to sub.example.com. NS ... then
                 * we do not know, since example.com. may be in between. */
-               for(i=0; i<msg->rep->an_numrrsets+msg->rep->ns_numrrsets; 
+               for(i=0; i<msg->rep->an_numrrsets+msg->rep->ns_numrrsets;
                        i++) {
                        struct ub_packed_rrset_key* s = msg->rep->rrsets[i];
                        if(ntohs(s->rk.type) == LDNS_RR_TYPE_NS &&
@@ -890,7 +891,7 @@ int iter_msg_from_zone(struct dns_msg* msg, struct delegpt* dp,
                return 0;
        }
        log_assert(type==RESPONSE_TYPE_ANSWER || type==RESPONSE_TYPE_CNAME);
-       /* not a referral, and not lame delegation (upwards), so, 
+       /* not a referral, and not lame delegation (upwards), so,
         * any NS rrset must be from the zone itself */
        if(reply_find_rrset_section_an(msg->rep, dp->name, dp->namelen,
                LDNS_RR_TYPE_NS, dclass) ||
@@ -906,7 +907,7 @@ int iter_msg_from_zone(struct dns_msg* msg, struct delegpt* dp,
 }
 
 /**
- * check equality of two rrsets 
+ * check equality of two rrsets
  * @param k1: rrset
  * @param k2: rrset
  * @return true if equal
@@ -935,7 +936,7 @@ rrset_equal(struct ub_packed_rrset_key* k1, struct ub_packed_rrset_key* k2)
        for(i=0; i<t; i++) {
                if(d1->rr_len[i] != d2->rr_len[i] ||
                        /* no ttl check: d1->rr_ttl[i] != d2->rr_ttl[i] ||*/
-                       memcmp(d1->rr_data[i], d2->rr_data[i], 
+                       memcmp(d1->rr_data[i], d2->rr_data[i],
                                d1->rr_len[i]) != 0)
                        return 0;
        }
@@ -966,7 +967,7 @@ rrset_canonical_sort_cmp(const void* x, const void* y)
        return 0;
 }
 
-int 
+int
 reply_equal(struct reply_info* p, struct reply_info* q, struct regional* region)
 {
        size_t i;
@@ -1024,7 +1025,7 @@ reply_equal(struct reply_info* p, struct reply_info* q, struct regional* region)
        return 1;
 }
 
-void 
+void
 caps_strip_reply(struct reply_info* rep)
 {
        size_t i;
@@ -1066,8 +1067,8 @@ int caps_failed_rcode(struct reply_info* rep)
                FLAGS_GET_RCODE(rep->flags) == LDNS_RCODE_NXDOMAIN);
 }
 
-void 
-iter_store_parentside_rrset(struct module_env* env, 
+void
+iter_store_parentside_rrset(struct module_env* env,
        struct ub_packed_rrset_key* rrset)
 {
        struct rrset_ref ref;
@@ -1107,12 +1108,12 @@ iter_store_parentside_NS(struct module_env* env, struct reply_info* rep)
        }
 }
 
-void iter_store_parentside_neg(struct module_env* env, 
+void iter_store_parentside_neg(struct module_env* env,
         struct query_info* qinfo, struct reply_info* rep)
 {
        /* TTL: NS from referral in iq->deleg_msg,
         *      or first RR from iq->response,
-        *      or servfail5secs if !iq->response */ 
+        *      or servfail5secs if !iq->response */
        time_t ttl = NORR_TTL;
        struct ub_packed_rrset_key* neg;
        struct packed_rrset_data* newd;
@@ -1133,7 +1134,7 @@ void iter_store_parentside_neg(struct module_env* env,
        neg->rk.type = htons(qinfo->qtype);
        neg->rk.rrset_class = htons(qinfo->qclass);
        neg->rk.flags = 0;
-       neg->rk.dname = regional_alloc_init(env->scratch, qinfo->qname, 
+       neg->rk.dname = regional_alloc_init(env->scratch, qinfo->qname,
                qinfo->qname_len);
        if(!neg->rk.dname) {
                log_err("out of memory in store_parentside_neg");
@@ -1141,7 +1142,7 @@ void iter_store_parentside_neg(struct module_env* env,
        }
        neg->rk.dname_len = qinfo->qname_len;
        neg->entry.hash = rrset_key_hash(&neg->rk);
-       newd = (struct packed_rrset_data*)regional_alloc_zero(env->scratch, 
+       newd = (struct packed_rrset_data*)regional_alloc_zero(env->scratch,
                sizeof(struct packed_rrset_data) + sizeof(size_t) +
                sizeof(uint8_t*) + sizeof(time_t) + sizeof(uint16_t));
        if(!newd) {
@@ -1166,13 +1167,13 @@ void iter_store_parentside_neg(struct module_env* env,
        iter_store_parentside_rrset(env, neg);
 }
 
-int 
+int
 iter_lookup_parent_NS_from_cache(struct module_env* env, struct delegpt* dp,
        struct regional* region, struct query_info* qinfo)
 {
        struct ub_packed_rrset_key* akey;
-       akey = rrset_cache_lookup(env->rrset_cache, dp->name, 
-               dp->namelen, LDNS_RR_TYPE_NS, qinfo->qclass, 
+       akey = rrset_cache_lookup(env->rrset_cache, dp->name,
+               dp->namelen, LDNS_RR_TYPE_NS, qinfo->qclass,
                PACKED_RRSET_PARENT_SIDE, *env->now, 0);
        if(akey) {
                log_rrset_key(VERB_ALGO, "found parent-side NS in cache", akey);
@@ -1195,8 +1196,8 @@ int iter_lookup_parent_glue_from_cache(struct module_env* env,
        size_t num = delegpt_count_targets(dp);
        for(ns = dp->nslist; ns; ns = ns->next) {
                /* get cached parentside A */
-               akey = rrset_cache_lookup(env->rrset_cache, ns->name, 
-                       ns->namelen, LDNS_RR_TYPE_A, qinfo->qclass, 
+               akey = rrset_cache_lookup(env->rrset_cache, ns->name,
+                       ns->namelen, LDNS_RR_TYPE_A, qinfo->qclass,
                        PACKED_RRSET_PARENT_SIDE, *env->now, 0);
                if(akey) {
                        log_rrset_key(VERB_ALGO, "found parent-side", akey);
@@ -1207,8 +1208,8 @@ int iter_lookup_parent_glue_from_cache(struct module_env* env,
                        lock_rw_unlock(&akey->entry.lock);
                }
                /* get cached parentside AAAA */
-               akey = rrset_cache_lookup(env->rrset_cache, ns->name, 
-                       ns->namelen, LDNS_RR_TYPE_AAAA, qinfo->qclass, 
+               akey = rrset_cache_lookup(env->rrset_cache, ns->name,
+                       ns->namelen, LDNS_RR_TYPE_AAAA, qinfo->qclass,
                        PACKED_RRSET_PARENT_SIDE, *env->now, 0);
                if(akey) {
                        log_rrset_key(VERB_ALGO, "found parent-side", akey);
@@ -1223,8 +1224,8 @@ int iter_lookup_parent_glue_from_cache(struct module_env* env,
        return delegpt_count_targets(dp) != num;
 }
 
-int 
-iter_get_next_root(struct iter_hints* hints, struct iter_forwards* fwd, 
+int
+iter_get_next_root(struct iter_hints* hints, struct iter_forwards* fwd,
        uint16_t* c)
 {
        uint16_t c1 = *c, c2 = *c;
@@ -1246,7 +1247,7 @@ void
 iter_scrub_ds(struct dns_msg* msg, struct ub_packed_rrset_key* ns, uint8_t* z)
 {
        /* Only the DS record for the delegation itself is expected.
-        * We allow DS for everything between the bailiwick and the 
+        * We allow DS for everything between the bailiwick and the
         * zonecut, thus DS records must be at or above the zonecut.
         * And the DS records must be below the server authority zone.
         * The answer section is already scrubbed. */
@@ -1260,7 +1261,7 @@ iter_scrub_ds(struct dns_msg* msg, struct ub_packed_rrset_key* ns, uint8_t* z)
                                s->rk.dname, ntohs(s->rk.type),
                                ntohs(s->rk.rrset_class));
                        memmove(msg->rep->rrsets+i, msg->rep->rrsets+i+1,
-                               sizeof(struct ub_packed_rrset_key*) * 
+                               sizeof(struct ub_packed_rrset_key*) *
                                (msg->rep->rrset_count-i-1));
                        msg->rep->ns_numrrsets--;
                        msg->rep->rrset_count--;
@@ -1284,11 +1285,11 @@ iter_scrub_nxdomain(struct dns_msg* msg)
        msg->rep->an_numrrsets = 0;
 }
 
-void iter_dec_attempts(struct delegpt* dp, int d)
+void iter_dec_attempts(struct delegpt* dp, int d, int outbound_msg_retry)
 {
        struct delegpt_addr* a;
        for(a=dp->target_list; a; a = a->next_target) {
-               if(a->attempts >= OUTBOUND_MSG_RETRY) {
+               if(a->attempts >= outbound_msg_retry) {
                        /* add back to result list */
                        a->next_result = dp->result_list;
                        dp->result_list = a;
@@ -1299,7 +1300,8 @@ void iter_dec_attempts(struct delegpt* dp, int d)
        }
 }
 
-void iter_merge_retry_counts(struct delegpt* dp, struct delegpt* old)
+void iter_merge_retry_counts(struct delegpt* dp, struct delegpt* old,
+       int outbound_msg_retry)
 {
        struct delegpt_addr* a, *o, *prev;
        for(a=dp->target_list; a; a = a->next_target) {
@@ -1313,7 +1315,7 @@ void iter_merge_retry_counts(struct delegpt* dp, struct delegpt* old)
        prev = NULL;
        a = dp->usable_list;
        while(a) {
-               if(a->attempts >= OUTBOUND_MSG_RETRY) {
+               if(a->attempts >= outbound_msg_retry) {
                        log_addr(VERB_ALGO, "remove from usable list dp",
                                &a->addr, a->addrlen);
                        /* remove from result list */
index 509d292..0a40916 100644 (file)
@@ -347,16 +347,19 @@ void iter_scrub_nxdomain(struct dns_msg* msg);
  * Remove query attempts from all available ips. For 0x20.
  * @param dp: delegpt.
  * @param d: decrease.
+ * @param outbound_msg_retry: number of retries of outgoing queries
  */
-void iter_dec_attempts(struct delegpt* dp, int d);
+void iter_dec_attempts(struct delegpt* dp, int d, int outbound_msg_retry);
 
 /**
  * Add retry counts from older delegpt to newer delegpt.
  * Does not waste time on timeout'd (or other failing) addresses.
  * @param dp: new delegationpoint.
  * @param old: old delegationpoint.
+ * @param outbound_msg_retry: number of retries of outgoing queries
  */
-void iter_merge_retry_counts(struct delegpt* dp, struct delegpt* old);
+void iter_merge_retry_counts(struct delegpt* dp, struct delegpt* old,
+       int outbound_msg_retry);
 
 /**
  * See if a DS response (type ANSWER) is too low: a nodata answer with 
index f0105ad..5400694 100644 (file)
@@ -1533,36 +1533,6 @@ processInitRequest(struct module_qstate* qstate, struct iter_qstate* iq,
                if(!iq->ratelimit_ok && qstate->prefetch_leeway)
                        iq->ratelimit_ok = 1; /* allow prefetches, this keeps
                        otherwise valid data in the cache */
-               if(!iq->ratelimit_ok && infra_ratelimit_exceeded(
-                       qstate->env->infra_cache, iq->dp->name,
-                       iq->dp->namelen, *qstate->env->now)) {
-                       /* and increment the rate, so that the rate for time
-                        * now will also exceed the rate, keeping cache fresh */
-                       (void)infra_ratelimit_inc(qstate->env->infra_cache,
-                               iq->dp->name, iq->dp->namelen,
-                               *qstate->env->now, &qstate->qinfo,
-                               qstate->reply);
-                       /* see if we are passed through with slip factor */
-                       if(qstate->env->cfg->ratelimit_factor != 0 &&
-                               ub_random_max(qstate->env->rnd,
-                                   qstate->env->cfg->ratelimit_factor) == 1) {
-                               iq->ratelimit_ok = 1;
-                               log_nametypeclass(VERB_ALGO, "ratelimit allowed through for "
-                                       "delegation point", iq->dp->name,
-                                       LDNS_RR_TYPE_NS, LDNS_RR_CLASS_IN);
-                       } else {
-                               lock_basic_lock(&ie->queries_ratelimit_lock);
-                               ie->num_queries_ratelimited++;
-                               lock_basic_unlock(&ie->queries_ratelimit_lock);
-                               log_nametypeclass(VERB_ALGO, "ratelimit exceeded with "
-                                       "delegation point", iq->dp->name,
-                                       LDNS_RR_TYPE_NS, LDNS_RR_CLASS_IN);
-                               qstate->was_ratelimited = 1;
-                               errinf(qstate, "query was ratelimited");
-                               errinf_dname(qstate, "for zone", iq->dp->name);
-                               return error_response(qstate, id, LDNS_RCODE_SERVFAIL);
-                       }
-               }
 
                /* see if this dp not useless.
                 * It is useless if:
@@ -1988,12 +1958,13 @@ processLastResort(struct module_qstate* qstate, struct iter_qstate* iq,
                        iq->chase_flags &= ~BIT_RD; /* go to authorities */
                        for(ns = p->nslist; ns; ns=ns->next) {
                                (void)delegpt_add_ns(iq->dp, qstate->region,
-                                       ns->name, ns->lame);
+                                       ns->name, ns->lame, ns->tls_auth_name,
+                                       ns->port);
                        }
                        for(a = p->target_list; a; a=a->next_target) {
                                (void)delegpt_add_addr(iq->dp, qstate->region,
                                        &a->addr, a->addrlen, a->bogus,
-                                       a->lame, a->tls_auth_name, NULL);
+                                       a->lame, a->tls_auth_name, -1, NULL);
                        }
                }
                iq->dp->has_parent_side_NS = 1;
@@ -2211,9 +2182,11 @@ processQueryTargets(struct module_qstate* qstate, struct iter_qstate* iq,
        int auth_fallback = 0;
        uint8_t* qout_orig = NULL;
        size_t qout_orig_len = 0;
+       int sq_check_ratelimit = 1;
+       int sq_was_ratelimited = 0;
 
-       /* NOTE: a request will encounter this state for each target it 
-        * needs to send a query to. That is, at least one per referral, 
+       /* NOTE: a request will encounter this state for each target it
+        * needs to send a query to. That is, at least one per referral,
         * more if some targets timeout or return throwaway answers. */
 
        log_query_info(VERB_QUERY, "processQueryTargets:", &qstate->qinfo);
@@ -2298,7 +2271,7 @@ processQueryTargets(struct module_qstate* qstate, struct iter_qstate* iq,
                iq->minimise_count++;
                iq->timeout_count = 0;
 
-               iter_dec_attempts(iq->dp, 1);
+               iter_dec_attempts(iq->dp, 1, ie->outbound_msg_retry);
 
                /* Limit number of iterations for QNAMEs with more
                 * than MAX_MINIMISE_COUNT labels. Send first MINIMISE_ONE_LAB
@@ -2500,7 +2473,7 @@ processQueryTargets(struct module_qstate* qstate, struct iter_qstate* iq,
                                (int)iq->caps_server+1, (int)naddr*3);
                        iq->response = iq->caps_response;
                        iq->caps_fallback = 0;
-                       iter_dec_attempts(iq->dp, 3); /* space for fallback */
+                       iter_dec_attempts(iq->dp, 3, ie->outbound_msg_retry); /* space for fallback */
                        iq->num_current_queries++; /* RespState decrements it*/
                        iq->referral_count++; /* make sure we don't loop */
                        iq->sent_count = 0;
@@ -2529,6 +2502,23 @@ processQueryTargets(struct module_qstate* qstate, struct iter_qstate* iq,
        /* Add the current set of unused targets to our queue. */
        delegpt_add_unused_targets(iq->dp);
 
+       if(qstate->env->auth_zones) {
+               /* apply rpz triggers at query time */
+               struct dns_msg* forged_response = rpz_callback_from_iterator_module(qstate, iq);
+               if(forged_response != NULL) {
+                       qstate->ext_state[id] = module_finished;
+                       qstate->return_rcode = LDNS_RCODE_NOERROR;
+                       qstate->return_msg = forged_response;
+                       iq->response = forged_response;
+                       next_state(iq, FINISHED_STATE);
+                       if(!iter_prepend(iq, qstate->return_msg, qstate->region)) {
+                               log_err("rpz, prepend rrsets: out of memory");
+                               return error_response(qstate, id, LDNS_RCODE_SERVFAIL);
+                       }
+                       return 0;
+               }
+       }
+
        /* Select the next usable target, filtering out unsuitable targets. */
        target = iter_server_selection(ie, qstate->env, iq->dp, 
                iq->dp->name, iq->dp->namelen, iq->qchase.qtype,
@@ -2588,7 +2578,7 @@ processQueryTargets(struct module_qstate* qstate, struct iter_qstate* iq,
                                                (int)iq->caps_server+1);
                                        iq->response = iq->caps_response;
                                        iq->caps_fallback = 0;
-                                       iter_dec_attempts(iq->dp, 3); /* space for fallback */
+                                       iter_dec_attempts(iq->dp, 3, ie->outbound_msg_retry); /* space for fallback */
                                        iq->num_current_queries++; /* RespState decrements it*/
                                        iq->referral_count++; /* make sure we don't loop */
                                        iq->sent_count = 0;
@@ -2629,22 +2619,9 @@ processQueryTargets(struct module_qstate* qstate, struct iter_qstate* iq,
                return 0;
        }
 
-       /* if not forwarding, check ratelimits per delegationpoint name */
-       if(!(iq->chase_flags & BIT_RD) && !iq->ratelimit_ok) {
-               if(!infra_ratelimit_inc(qstate->env->infra_cache, iq->dp->name,
-                       iq->dp->namelen, *qstate->env->now, &qstate->qinfo,
-                       qstate->reply)) {
-                       lock_basic_lock(&ie->queries_ratelimit_lock);
-                       ie->num_queries_ratelimited++;
-                       lock_basic_unlock(&ie->queries_ratelimit_lock);
-                       verbose(VERB_ALGO, "query exceeded ratelimits");
-                       qstate->was_ratelimited = 1;
-                       errinf_dname(qstate, "exceeded ratelimit for zone",
-                               iq->dp->name);
-                       return error_response(qstate, id, LDNS_RCODE_SERVFAIL);
-               }
-       }
-
+       /* Do not check ratelimit for forwarding queries or if we already got a
+        * pass. */
+       sq_check_ratelimit = (!(iq->chase_flags & BIT_RD) && !iq->ratelimit_ok);
        /* We have a valid target. */
        if(verbosity >= VERB_QUERY) {
                log_query_info(VERB_QUERY, "sending query:", &iq->qinfo_out);
@@ -2656,24 +2633,32 @@ processQueryTargets(struct module_qstate* qstate, struct iter_qstate* iq,
        }
        fptr_ok(fptr_whitelist_modenv_send_query(qstate->env->send_query));
        outq = (*qstate->env->send_query)(&iq->qinfo_out,
-               iq->chase_flags | (iq->chase_to_rd?BIT_RD:0), 
+               iq->chase_flags | (iq->chase_to_rd?BIT_RD:0),
                /* unset CD if to forwarder(RD set) and not dnssec retry
                 * (blacklist nonempty) and no trust-anchors are configured
                 * above the qname or on the first attempt when dnssec is on */
                EDNS_DO| ((iq->chase_to_rd||(iq->chase_flags&BIT_RD)!=0)&&
                !qstate->blacklist&&(!iter_qname_indicates_dnssec(qstate->env,
-               &iq->qinfo_out)||target->attempts==1)?0:BIT_CD), 
+               &iq->qinfo_out)||target->attempts==1)?0:BIT_CD),
                iq->dnssec_expected, iq->caps_fallback || is_caps_whitelisted(
-               ie, iq), &target->addr, target->addrlen,
+               ie, iq), sq_check_ratelimit, &target->addr, target->addrlen,
                iq->dp->name, iq->dp->namelen,
+               (iq->dp->tcp_upstream || qstate->env->cfg->tcp_upstream),
                (iq->dp->ssl_upstream || qstate->env->cfg->ssl_upstream),
-               target->tls_auth_name, qstate);
+               target->tls_auth_name, qstate, &sq_was_ratelimited);
        if(!outq) {
+               if(sq_was_ratelimited) {
+                       lock_basic_lock(&ie->queries_ratelimit_lock);
+                       ie->num_queries_ratelimited++;
+                       lock_basic_unlock(&ie->queries_ratelimit_lock);
+                       verbose(VERB_ALGO, "query exceeded ratelimits");
+                       qstate->was_ratelimited = 1;
+                       errinf_dname(qstate, "exceeded ratelimit for zone",
+                               iq->dp->name);
+                       return error_response(qstate, id, LDNS_RCODE_SERVFAIL);
+               }
                log_addr(VERB_QUERY, "error sending query to auth server",
                        &target->addr, target->addrlen);
-               if(!(iq->chase_flags & BIT_RD) && !iq->ratelimit_ok)
-                   infra_ratelimit_dec(qstate->env->infra_cache, iq->dp->name,
-                       iq->dp->namelen, *qstate->env->now);
                if(qstate->env->cfg->qname_minimisation)
                        iq->minimisation_state = SKIP_MINIMISE_STATE;
                return next_state(iq, QUERYTARGETS_STATE);
@@ -2707,6 +2692,7 @@ find_NS(struct reply_info* rep, size_t from, size_t to)
  * 
  * @param qstate: query state.
  * @param iq: iterator query state.
+ * @param ie: iterator shared global environment.
  * @param id: module id.
  * @return true if the event requires more immediate processing, false if
  *         not. This is generally only true when forwarding the request to
@@ -2714,10 +2700,11 @@ find_NS(struct reply_info* rep, size_t from, size_t to)
  */
 static int
 processQueryResponse(struct module_qstate* qstate, struct iter_qstate* iq,
-       int id)
+       struct iter_env* ie, int id)
 {
        int dnsseclame = 0;
        enum response_type type;
+
        iq->num_current_queries--;
 
        if(!inplace_cb_query_response_call(qstate->env, qstate, iq->response))
@@ -2915,14 +2902,6 @@ processQueryResponse(struct module_qstate* qstate, struct iter_qstate* iq,
                 * delegation point, and back to the QUERYTARGETS_STATE. */
                verbose(VERB_DETAIL, "query response was REFERRAL");
 
-               if(!(iq->chase_flags & BIT_RD) && !iq->ratelimit_ok) {
-                       /* we have a referral, no ratelimit, we can send
-                        * our queries to the given name */
-                       infra_ratelimit_dec(qstate->env->infra_cache,
-                               iq->dp->name, iq->dp->namelen,
-                               *qstate->env->now);
-               }
-
                /* if hardened, only store referral if we asked for it */
                if(!qstate->no_cache_store &&
                (!qstate->env->cfg->harden_referral_path ||
@@ -2983,7 +2962,8 @@ processQueryResponse(struct module_qstate* qstate, struct iter_qstate* iq,
                }
                if(iq->store_parent_NS && query_dname_compare(iq->dp->name,
                        iq->store_parent_NS->name) == 0)
-                       iter_merge_retry_counts(iq->dp, iq->store_parent_NS);
+                       iter_merge_retry_counts(iq->dp, iq->store_parent_NS,
+                               ie->outbound_msg_retry);
                delegpt_log(VERB_ALGO, iq->dp);
                /* Count this as a referral. */
                iq->referral_count++;
@@ -3061,6 +3041,39 @@ processQueryResponse(struct module_qstate* qstate, struct iter_qstate* iq,
                /* set the current request's qname to the new value. */
                iq->qchase.qname = sname;
                iq->qchase.qname_len = snamelen;
+               if(qstate->env->auth_zones) {
+                       /* apply rpz qname triggers after cname */
+                       struct dns_msg* forged_response =
+                               rpz_callback_from_iterator_cname(qstate, iq);
+                       while(forged_response && reply_find_rrset_section_an(
+                               forged_response->rep, iq->qchase.qname,
+                               iq->qchase.qname_len, LDNS_RR_TYPE_CNAME,
+                               iq->qchase.qclass)) {
+                               /* another cname to follow */
+                               if(!handle_cname_response(qstate, iq, forged_response,
+                                       &sname, &snamelen)) {
+                                       errinf(qstate, "malloc failure, CNAME info");
+                                       return error_response(qstate, id, LDNS_RCODE_SERVFAIL);
+                               }
+                               iq->qchase.qname = sname;
+                               iq->qchase.qname_len = snamelen;
+                               forged_response =
+                                       rpz_callback_from_iterator_cname(qstate, iq);
+                       }
+                       if(forged_response != NULL) {
+                               qstate->ext_state[id] = module_finished;
+                               qstate->return_rcode = LDNS_RCODE_NOERROR;
+                               qstate->return_msg = forged_response;
+                               iq->response = forged_response;
+                               next_state(iq, FINISHED_STATE);
+                               if(!iter_prepend(iq, qstate->return_msg, qstate->region)) {
+                                       log_err("rpz after cname, prepend rrsets: out of memory");
+                                       return error_response(qstate, id, LDNS_RCODE_SERVFAIL);
+                               }
+                               qstate->return_msg->qinfo = qstate->qinfo;
+                               return 0;
+                       }
+               }
                /* Clear the query state, since this is a query restart. */
                iq->deleg_msg = NULL;
                iq->dp = NULL;
@@ -3188,7 +3201,7 @@ prime_supers(struct module_qstate* qstate, int id, struct module_qstate* forq)
        /* Convert our response to a delegation point */
        dp = delegpt_from_message(qstate->return_msg, forq->region);
        if(!dp) {
-               /* if there is no convertable delegation point, then 
+               /* if there is no convertible delegation point, then 
                 * the ANSWER type was (presumably) a negative answer. */
                verbose(VERB_ALGO, "prime response was not a positive "
                        "ANSWER; failing");
@@ -3330,21 +3343,22 @@ processTargetResponse(struct module_qstate* qstate, int id,
                        log_err("out of memory adding pside glue");
        }
 
-       /* This response is relevant to the current query, so we 
-        * add (attempt to add, anyway) this target(s) and reactivate 
-        * the original event. 
-        * NOTE: we could only look for the AnswerRRset if the 
+       /* This response is relevant to the current query, so we
+        * add (attempt to add, anyway) this target(s) and reactivate
+        * the original event.
+        * NOTE: we could only look for the AnswerRRset if the
         * response type was ANSWER. */
        rrset = reply_find_answer_rrset(&iq->qchase, qstate->return_msg->rep);
        if(rrset) {
                int additions = 0;
                /* if CNAMEs have been followed - add new NS to delegpt. */
                /* BTW. RFC 1918 says NS should not have got CNAMEs. Robust. */
-               if(!delegpt_find_ns(foriq->dp, rrset->rk.dname, 
+               if(!delegpt_find_ns(foriq->dp, rrset->rk.dname,
                        rrset->rk.dname_len)) {
                        /* if dpns->lame then set newcname ns lame too */
-                       if(!delegpt_add_ns(foriq->dp, forq->region, 
-                               rrset->rk.dname, dpns->lame))
+                       if(!delegpt_add_ns(foriq->dp, forq->region,
+                               rrset->rk.dname, dpns->lame, dpns->tls_auth_name,
+                               dpns->port))
                                log_err("out of memory adding cnamed-ns");
                }
                /* if dpns->lame then set the address(es) lame too */
@@ -3694,7 +3708,7 @@ iter_handle(struct module_qstate* qstate, struct iter_qstate* iq,
                                cont = processQueryTargets(qstate, iq, ie, id);
                                break;
                        case QUERY_RESP_STATE:
-                               cont = processQueryResponse(qstate, iq, id);
+                               cont = processQueryResponse(qstate, iq, ie, id);
                                break;
                        case PRIME_RESP_STATE:
                                cont = processPrimeResponse(qstate, id);
@@ -3764,7 +3778,7 @@ process_response(struct module_qstate* qstate, struct iter_qstate* iq,
                        iq->num_current_queries--;
                        /* need fresh attempts for the 0x20 fallback, if
                         * that was the cause for the failure */
-                       iter_dec_attempts(iq->dp, 3);
+                       iter_dec_attempts(iq->dp, 3, ie->outbound_msg_retry);
                        verbose(VERB_DETAIL, "Capsforid: timeouts, starting fallback");
                        goto handle_it;
                }
@@ -3798,15 +3812,15 @@ process_response(struct module_qstate* qstate, struct iter_qstate* iq,
                goto handle_it;
        }
        /* edns is not examined, but removed from message to help cache */
-       if(parse_extract_edns(prs, &edns, qstate->env->scratch) !=
+       if(parse_extract_edns_from_response_msg(prs, &edns, qstate->env->scratch) !=
                LDNS_RCODE_NOERROR) {
                iq->parse_failures++;
                goto handle_it;
        }
 
        /* Copy the edns options we may got from the back end */
-       if(edns.opt_list) {
-               qstate->edns_opts_back_in = edns_opt_copy_region(edns.opt_list,
+       if(edns.opt_list_in) {
+               qstate->edns_opts_back_in = edns_opt_copy_region(edns.opt_list_in,
                        qstate->region);
                if(!qstate->edns_opts_back_in) {
                        log_err("out of memory on incoming message");
index dc5e575..8b84052 100644 (file)
@@ -80,7 +80,7 @@ struct rbtree_type;
 /**
  * number of labels from QNAME that are always send individually when using
  * QNAME minimisation, even when the number of labels of the QNAME is bigger
- * tham MAX_MINIMISE_COUNT */
+ * than MAX_MINIMISE_COUNT */
 #define MINIMISE_ONE_LAB       4
 #define MINIMISE_MULTIPLE_LABS (MAX_MINIMISE_COUNT - MINIMISE_ONE_LAB)
 /** at what query-sent-count to stop target fetch policy */
@@ -94,8 +94,6 @@ extern int UNKNOWN_SERVER_NICENESS;
  * Equals RTT_MAX_TIMEOUT
  */
 #define USEFUL_SERVER_TOP_TIMEOUT      120000
-/** number of retries on outgoing queries */
-#define OUTBOUND_MSG_RETRY 5
 /** RTT band, within this amount from the best, servers are chosen randomly.
  * Chosen so that the UNKNOWN_SERVER_NICENESS falls within the band of a 
  * fast server, this causes server exploration as a side benefit. msec. */
@@ -139,6 +137,9 @@ struct iter_env {
        lock_basic_type queries_ratelimit_lock;
        /** number of queries that have been ratelimited */
        size_t num_queries_ratelimited;
+
+       /** number of retries on outgoing queries */
+       int outbound_msg_retry;
 };
 
 /**
@@ -378,7 +379,7 @@ struct iter_qstate {
        /** list of pending queries to authoritative servers. */
        struct outbound_list outlist;
 
-       /** QNAME minimisation state, RFC7816 */
+       /** QNAME minimisation state, RFC9156 */
        enum minimisation_state minimisation_state;
 
        /** State for capsfail: QNAME minimisation state for comparisons. */
index e589c6a..c8d911f 100644 (file)
@@ -48,6 +48,7 @@
 #include "services/cache/rrset.h"
 #include "services/cache/infra.h"
 #include "services/authzone.h"
+#include "services/listen_dnsport.h"
 #include "util/data/msgreply.h"
 #include "util/storage/slabhash.h"
 #include "util/edns.h"
@@ -73,6 +74,7 @@ context_finalize(struct ub_ctx* ctx)
        config_apply(cfg);
        if(!modstack_setup(&ctx->mods, cfg->module_conf, ctx->env))
                return UB_INITFAIL;
+       listen_setup_locks();
        log_edns_known_options(VERB_ALGO, ctx->env);
        ctx->local_zones = local_zones_create();
        if(!ctx->local_zones)
index 78f8731..c0c86fb 100644 (file)
@@ -176,35 +176,6 @@ struct ctx_query {
        struct ub_result* res;
 };
 
-/**
- * The error constants
- */
-enum ub_ctx_err {
-       /** no error */
-       UB_NOERROR = 0,
-       /** socket operation. Set to -1, so that if an error from _fd() is
-        * passed (-1) it gives a socket error. */
-       UB_SOCKET = -1,
-       /** alloc failure */
-       UB_NOMEM = -2,
-       /** syntax error */
-       UB_SYNTAX = -3,
-       /** DNS service failed */
-       UB_SERVFAIL = -4,
-       /** fork() failed */
-       UB_FORKFAIL = -5,
-       /** cfg change after finalize() */
-       UB_AFTERFINAL = -6,
-       /** initialization failed (bad settings) */
-       UB_INITFAIL = -7,
-       /** error in pipe communication with async bg worker */
-       UB_PIPE = -8,
-       /** error reading from file (resolv.conf) */
-       UB_READFILE = -9,
-       /** error async_id does not exist or result already been delivered */
-       UB_NOID = -10
-};
-
 /**
  * Command codes for libunbound pipe.
  *
index c9e24ba..038b7b9 100644 (file)
@@ -64,6 +64,7 @@
 #include "services/cache/infra.h"
 #include "services/cache/rrset.h"
 #include "services/authzone.h"
+#include "services/listen_dnsport.h"
 #include "sldns/sbuffer.h"
 #ifdef HAVE_PTHREAD
 #include <signal.h>
@@ -185,6 +186,7 @@ ub_ctx_create(void)
                ub_randfree(ctx->seed_rnd);
                config_delete(ctx->env->cfg);
                modstack_desetup(&ctx->mods, ctx->env);
+               listen_desetup_locks();
                edns_known_options_delete(ctx->env);
                edns_strings_delete(ctx->env->edns_strings);
                free(ctx->env);
@@ -198,6 +200,7 @@ ub_ctx_create(void)
                ub_randfree(ctx->seed_rnd);
                config_delete(ctx->env->cfg);
                modstack_desetup(&ctx->mods, ctx->env);
+               listen_desetup_locks();
                edns_known_options_delete(ctx->env);
                edns_strings_delete(ctx->env->edns_strings);
                free(ctx->env);
@@ -344,6 +347,7 @@ ub_ctx_delete(struct ub_ctx* ctx)
        }
        ub_randfree(ctx->seed_rnd);
        alloc_clear(&ctx->superalloc);
+       listen_desetup_locks();
        traverse_postorder(&ctx->queries, delq, NULL);
        if(ctx_logfile_overridden) {
                log_file(NULL);
index 8a9ca94..ab28dd5 100644 (file)
@@ -600,7 +600,9 @@ setup_qinfo_edns(struct libworker* w, struct ctx_query* q,
        edns->ext_rcode = 0;
        edns->edns_version = 0;
        edns->bits = EDNS_DO;
-       edns->opt_list = NULL;
+       edns->opt_list_in = NULL;
+       edns->opt_list_out = NULL;
+       edns->opt_list_inplace_cb_out = NULL;
        edns->padding_block_size = 0;
        if(sldns_buffer_capacity(w->back->udp_buff) < 65535)
                edns->udp_size = (uint16_t)sldns_buffer_capacity(
@@ -880,9 +882,10 @@ void libworker_alloc_cleanup(void* arg)
 
 struct outbound_entry* libworker_send_query(struct query_info* qinfo,
        uint16_t flags, int dnssec, int want_dnssec, int nocaps,
+       int check_ratelimit,
        struct sockaddr_storage* addr, socklen_t addrlen, uint8_t* zone,
-       size_t zonelen, int ssl_upstream, char* tls_auth_name,
-       struct module_qstate* q)
+       size_t zonelen, int tcp_upstream, int ssl_upstream, char* tls_auth_name,
+       struct module_qstate* q, int* was_ratelimited)
 {
        struct libworker* w = (struct libworker*)q->env->worker;
        struct outbound_entry* e = (struct outbound_entry*)regional_alloc(
@@ -891,9 +894,10 @@ struct outbound_entry* libworker_send_query(struct query_info* qinfo,
                return NULL;
        e->qstate = q;
        e->qsent = outnet_serviced_query(w->back, qinfo, flags, dnssec,
-               want_dnssec, nocaps, q->env->cfg->tcp_upstream, ssl_upstream,
+               want_dnssec, nocaps, check_ratelimit, tcp_upstream, ssl_upstream,
                tls_auth_name, addr, addrlen, zone, zonelen, q,
-               libworker_handle_service_reply, e, w->back->udp_buff, q->env);
+               libworker_handle_service_reply, e, w->back->udp_buff, q->env,
+               was_ratelimited);
        if(!e->qsent) {
                return NULL;
        }
@@ -974,10 +978,11 @@ void worker_sighandler(int ATTR_UNUSED(sig), void* ATTR_UNUSED(arg))
 struct outbound_entry* worker_send_query(struct query_info* ATTR_UNUSED(qinfo),
        uint16_t ATTR_UNUSED(flags), int ATTR_UNUSED(dnssec),
        int ATTR_UNUSED(want_dnssec), int ATTR_UNUSED(nocaps),
+       int ATTR_UNUSED(check_ratelimit),
        struct sockaddr_storage* ATTR_UNUSED(addr), socklen_t ATTR_UNUSED(addrlen),
-       uint8_t* ATTR_UNUSED(zone), size_t ATTR_UNUSED(zonelen),
+       uint8_t* ATTR_UNUSED(zone), size_t ATTR_UNUSED(zonelen), int ATTR_UNUSED(tcp_upstream),
        int ATTR_UNUSED(ssl_upstream), char* ATTR_UNUSED(tls_auth_name),
-       struct module_qstate* ATTR_UNUSED(q))
+       struct module_qstate* ATTR_UNUSED(q), int* ATTR_UNUSED(was_ratelimited))
 {
        log_assert(0);
        return 0;
index 4d694b8..a5d5c03 100644 (file)
@@ -41,7 +41,7 @@
  *
  * Use ub_ctx_create_event_ub_base() to create an unbound context that uses
  * the user provided event base API.  Then, use the ub_resolve_event call
- * to add DNS resolve queries to the context.  Those then run whith the
+ * to add DNS resolve queries to the context.  Those then run with the
  * provided event_base, and when they are done you get a function callback.
  *
  * This method does not fork another process or create a thread, the effort
index 945c17a..ee85587 100644 (file)
@@ -224,7 +224,7 @@ struct ub_result {
  * It is called with
  *     void* my_arg: your pointer to a (struct of) data of your choice, 
  *             or NULL.
- *     int err: if 0 all is OK, otherwise an error occured and no results
+ *     int err: if 0 all is OK, otherwise an error occurred and no results
  *          are forthcoming.
  *     struct result: pointer to more detailed result structure.
  *             This structure is allocated on the heap and needs to be
@@ -232,6 +232,35 @@ struct ub_result {
  */
 typedef void (*ub_callback_type)(void*, int, struct ub_result*);
 
+/**
+ * The error constants
+ */
+enum ub_ctx_err {
+       /** no error */
+       UB_NOERROR = 0,
+       /** socket operation. Set to -1, so that if an error from _fd() is
+        * passed (-1) it gives a socket error. */
+       UB_SOCKET = -1,
+       /** alloc failure */
+       UB_NOMEM = -2,
+       /** syntax error */
+       UB_SYNTAX = -3,
+       /** DNS service failed */
+       UB_SERVFAIL = -4,
+       /** fork() failed */
+       UB_FORKFAIL = -5,
+       /** cfg change after finalize() */
+       UB_AFTERFINAL = -6,
+       /** initialization failed (bad settings) */
+       UB_INITFAIL = -7,
+       /** error in pipe communication with async bg worker */
+       UB_PIPE = -8,
+       /** error reading from file (resolv.conf) */
+       UB_READFILE = -9,
+       /** error async_id does not exist or result already been delivered */
+       UB_NOID = -10
+};
+
 /**
  * Create a resolving and validation context.
  * The information from /etc/resolv.conf and /etc/hosts is not utilised by
@@ -563,6 +592,7 @@ void ub_resolve_free(struct ub_result* result);
 /** 
  * Convert error value to a human readable string.
  * @param err: error code from one of the libunbound functions.
+ *     The error codes are from the type enum ub_ctx_err.
  * @return pointer to constant text string, zero terminated.
  */
 const char* ub_strerror(int err);
index bf74738..0fa5bfa 100644 (file)
@@ -58,22 +58,27 @@ struct query_info;
  * @param dnssec: if set, EDNS record will have DO bit set.
  * @param want_dnssec: signatures needed.
  * @param nocaps: ignore capsforid(if in config), do not perturb qname.
+ * @param check_ratelimit: if set, will check ratelimit before sending out.
  * @param addr: where to.
  * @param addrlen: length of addr.
  * @param zone: delegation point name.
  * @param zonelen: length of zone name wireformat dname.
+ * @param tcp_upstream: use TCP for upstream queries.
  * @param ssl_upstream: use SSL for upstream queries.
  * @param tls_auth_name: if ssl_upstream, use this name with TLS
  *     authentication.
- * @param q: wich query state to reactivate upon return.
+ * @param q: which query state to reactivate upon return.
+ * @param was_ratelimited: it will signal back if the query failed to pass the
+ *     ratelimit check.
  * @return: false on failure (memory or socket related). no query was
  *      sent.
  */
 struct outbound_entry* libworker_send_query(struct query_info* qinfo,
        uint16_t flags, int dnssec, int want_dnssec, int nocaps,
+       int check_ratelimit,
        struct sockaddr_storage* addr, socklen_t addrlen, uint8_t* zone,
-       size_t zonelen, int ssl_upstream, char* tls_auth_name,
-       struct module_qstate* q);
+       size_t zonelen, int tcp_upstream, int ssl_upstream, char* tls_auth_name,
+       struct module_qstate* q, int* was_ratelimited);
 
 /** process incoming serviced query replies from the network */
 int libworker_handle_service_reply(struct comm_point* c, void* arg, int error,
@@ -109,22 +114,27 @@ void worker_sighandler(int sig, void* arg);
  * @param dnssec: if set, EDNS record will have DO bit set.
  * @param want_dnssec: signatures needed.
  * @param nocaps: ignore capsforid(if in config), do not perturb qname.
+ * @param check_ratelimit: if set, will check ratelimit before sending out.
  * @param addr: where to.
  * @param addrlen: length of addr.
  * @param zone: wireformat dname of the zone.
  * @param zonelen: length of zone name.
+ * @param tcp_upstream: use TCP for upstream queries.
  * @param ssl_upstream: use SSL for upstream queries.
  * @param tls_auth_name: if ssl_upstream, use this name with TLS
  *     authentication.
- * @param q: wich query state to reactivate upon return.
+ * @param q: which query state to reactivate upon return.
+ * @param was_ratelimited: it will signal back if the query failed to pass the
+ *     ratelimit check.
  * @return: false on failure (memory or socket related). no query was
  *      sent.
  */
 struct outbound_entry* worker_send_query(struct query_info* qinfo,
        uint16_t flags, int dnssec, int want_dnssec, int nocaps,
+       int check_ratelimit,
        struct sockaddr_storage* addr, socklen_t addrlen, uint8_t* zone,
-       size_t zonelen, int ssl_upstream, char* tls_auth_name,
-       struct module_qstate* q);
+       size_t zonelen, int tcp_upstream, int ssl_upstream, char* tls_auth_name,
+       struct module_qstate* q, int* was_ratelimited);
 
 /** 
  * process control messages from the main thread. Frees the control 
index aae41f5..3d1b3fe 100644 (file)
@@ -25,6 +25,7 @@
 #include "respip/respip.h"
 #include "services/view.h"
 #include "sldns/rrdef.h"
+#include "util/data/dname.h"
 
 
 /** Subset of resp_addr.node, used for inform-variant logging */
@@ -483,8 +484,8 @@ respip_views_apply_cfg(struct views* vs, struct config_file* cfg,
  * This function returns the copied rrset key on success, and NULL on memory
  * allocation failure.
  */
-static struct ub_packed_rrset_key*
-copy_rrset(const struct ub_packed_rrset_key* key, struct regional* region)
+struct ub_packed_rrset_key*
+respip_copy_rrset(const struct ub_packed_rrset_key* key, struct regional* region)
 {
        struct ub_packed_rrset_key* ck = regional_alloc(region,
                sizeof(struct ub_packed_rrset_key));
@@ -602,7 +603,7 @@ rdata2sockaddr(const struct packed_rrset_data* rd, uint16_t rtype, size_t i,
  */
 static struct resp_addr*
 respip_addr_lookup(const struct reply_info *rep, struct respip_set* rs,
-       size_t* rrset_id)
+       size_t* rrset_id, size_t* rr_id)
 {
        size_t i;
        struct resp_addr* ra;
@@ -625,6 +626,7 @@ respip_addr_lookup(const struct reply_info *rep, struct respip_set* rs,
                                &ss, addrlen);
                        if(ra) {
                                *rrset_id = i;
+                               *rr_id = j;
                                lock_rw_rdlock(&ra->lock);
                                lock_rw_unlock(&rs->lock);
                                return ra;
@@ -635,43 +637,6 @@ respip_addr_lookup(const struct reply_info *rep, struct respip_set* rs,
        return NULL;
 }
 
-/*
- * Create a new reply_info based on 'rep'.  The new info is based on
- * the passed 'rep', but ignores any rrsets except for the first 'an_numrrsets'
- * RRsets in the answer section.  These answer rrsets are copied to the
- * new info, up to 'copy_rrsets' rrsets (which must not be larger than
- * 'an_numrrsets').  If an_numrrsets > copy_rrsets, the remaining rrsets array
- * entries will be kept empty so the caller can fill them later.  When rrsets
- * are copied, they are shallow copied.  The caller must ensure that the
- * copied rrsets are valid throughout its lifetime and must provide appropriate
- * mutex if it can be shared by multiple threads.
- */
-static struct reply_info *
-make_new_reply_info(const struct reply_info* rep, struct regional* region,
-       size_t an_numrrsets, size_t copy_rrsets)
-{
-       struct reply_info* new_rep;
-       size_t i;
-
-       /* create a base struct.  we specify 'insecure' security status as
-        * the modified response won't be DNSSEC-valid.  In our faked response
-        * the authority and additional sections will be empty (except possible
-        * EDNS0 OPT RR in the additional section appended on sending it out),
-        * so the total number of RRsets is an_numrrsets. */
-       new_rep = construct_reply_info_base(region, rep->flags,
-               rep->qdcount, rep->ttl, rep->prefetch_ttl,
-               rep->serve_expired_ttl, an_numrrsets, 0, 0, an_numrrsets,
-               sec_status_insecure);
-       if(!new_rep)
-               return NULL;
-       if(!reply_info_alloc_rrset_keys(new_rep, NULL, region))
-               return NULL;
-       for(i=0; i<copy_rrsets; i++)
-               new_rep->rrsets[i] = rep->rrsets[i];
-
-       return new_rep;
-}
-
 /**
  * See if response-ip or tag data should override the original answer rrset
  * (which is rep->rrsets[rrset_id]) and if so override it.
@@ -730,7 +695,7 @@ respip_data_answer(enum respip_action action,
                                "response-ip redirect with tag data [%d] %s",
                                tag, (tag<num_tags?tagname[tag]:"null"));
                        /* use copy_rrset() to 'normalize' memory layout */
-                       rp = copy_rrset(&r, region);
+                       rp = respip_copy_rrset(&r, region);
                        if(!rp)
                                return -1;
                }
@@ -743,7 +708,7 @@ respip_data_answer(enum respip_action action,
         * rename the dname for other actions than redirect.  This is because
         * response-ip-data isn't associated to any specific name. */
        if(rp == data) {
-               rp = copy_rrset(rp, region);
+               rp = respip_copy_rrset(rp, region);
                if(!rp)
                        return -1;
                rp->rk.dname = rep->rrsets[rrset_id]->rk.dname;
@@ -807,7 +772,6 @@ respip_nodata_answer(uint16_t qtype, enum respip_action action,
                 * is explicitly specified. */
                int rcode = (action == respip_always_nxdomain)?
                        LDNS_RCODE_NXDOMAIN:LDNS_RCODE_NOERROR;
-
                /* We should empty the answer section except for any preceding
                 * CNAMEs (in that case rrset_id > 0).  Type-ANY case is
                 * special as noted in respip_data_answer(). */
@@ -907,7 +871,7 @@ respip_rewrite_reply(const struct query_info* qinfo,
        size_t tag_datas_size;
        struct view* view = NULL;
        struct respip_set* ipset = NULL;
-       size_t rrset_id = 0;
+       size_t rrset_id = 0, rr_id = 0;
        enum respip_action action = respip_none;
        int tag = -1;
        struct resp_addr* raddr = NULL;
@@ -948,7 +912,7 @@ respip_rewrite_reply(const struct query_info* qinfo,
                lock_rw_rdlock(&view->lock);
                if(view->respip_set) {
                        if((raddr = respip_addr_lookup(rep,
-                               view->respip_set, &rrset_id))) {
+                               view->respip_set, &rrset_id, &rr_id))) {
                                /** for per-view respip directives the action
                                 * can only be direct (i.e. not tag-based) */
                                action = raddr->action;
@@ -962,7 +926,7 @@ respip_rewrite_reply(const struct query_info* qinfo,
                }
        }
        if(!raddr && (raddr = respip_addr_lookup(rep, ipset,
-               &rrset_id))) {
+               &rrset_id, &rr_id))) {
                action = (enum respip_action)local_data_find_tag_action(
                        raddr->taglist, raddr->taglen, ctaglist, ctaglen,
                        tag_actions, tag_actions_size,
@@ -976,7 +940,7 @@ respip_rewrite_reply(const struct query_info* qinfo,
                if(!r->taglist || taglist_intersect(r->taglist, 
                        r->taglistlen, ctaglist, ctaglen)) {
                        if((raddr = respip_addr_lookup(rep,
-                               r->respip_set, &rrset_id))) {
+                               r->respip_set, &rrset_id, &rr_id))) {
                                if(!respip_use_rpz(raddr, r, &action, &data,
                                        &rpz_log, &log_name, &rpz_cname_override,
                                        region, &rpz_used)) {
@@ -987,6 +951,21 @@ respip_rewrite_reply(const struct query_info* qinfo,
                                        return 0;
                                }
                                if(rpz_used) {
+                                       if(verbosity >= VERB_ALGO) {
+                                               struct sockaddr_storage ss;
+                                               socklen_t ss_len = 0;
+                                               char nm[256], ip[256];
+                                               char qn[255+1];
+                                               if(!rdata2sockaddr(rep->rrsets[rrset_id]->entry.data, ntohs(rep->rrsets[rrset_id]->rk.type), rr_id, &ss, &ss_len))
+                                                       snprintf(ip, sizeof(ip), "invalidRRdata");
+                                               else
+                                                       addr_to_str(&ss, ss_len, ip, sizeof(ip));
+                                               dname_str(qinfo->qname, qn);
+                                               addr_to_str(&raddr->node.addr,
+                                                       raddr->node.addrlen,
+                                                       nm, sizeof(nm));
+                                               verbose(VERB_ALGO, "respip: rpz response-ip trigger %s/%d on %s %s with action %s", nm, raddr->node.net, qn, ip, rpz_action_to_string(respip_action_to_rpz_action(action)));
+                                       }
                                        /* break to make sure 'a' stays pointed
                                         * to used auth_zone, and keeps lock */
                                        break;
@@ -1209,7 +1188,7 @@ respip_merge_cname(struct reply_info* base_rep,
        if(!new_rep)
                return 0;
        for(i=0,j=base_rep->an_numrrsets; i<tgt_rep->an_numrrsets; i++,j++) {
-               new_rep->rrsets[j] = copy_rrset(tgt_rep->rrsets[i], region);
+               new_rep->rrsets[j] = respip_copy_rrset(tgt_rep->rrsets[i], region);
                if(!new_rep->rrsets[j])
                        return 0;
        }
index bbd4714..3dfb4e9 100644 (file)
@@ -294,4 +294,7 @@ respip_enter_rr(struct regional* region, struct resp_addr* raddr,
  */
 void
 respip_sockaddr_delete(struct respip_set* set, struct resp_addr* node);
+
+struct ub_packed_rrset_key*
+respip_copy_rrset(const struct ub_packed_rrset_key* key, struct regional* region);
 #endif /* RESPIP_RESPIP_H */
index e6e3a8c..e83af53 100644 (file)
@@ -84,7 +84,7 @@
 #define AUTH_PROBE_TIMEOUT_STOP 1000 /* msec */
 /* auth transfer timeout for TCP connections, in msec */
 #define AUTH_TRANSFER_TIMEOUT 10000 /* msec */
-/* auth transfer max backoff for failed tranfers and probes */
+/* auth transfer max backoff for failed transfers and probes */
 #define AUTH_TRANSFER_MAX_BACKOFF 86400 /* sec */
 /* auth http port number */
 #define AUTH_HTTP_PORT 80
@@ -243,7 +243,7 @@ msg_add_rrset_an(struct auth_zone* z, struct regional* region,
        return 1;
 }
 
-/** add rrset to authority section (no additonal section rrsets yet) */
+/** add rrset to authority section (no additional section rrsets yet) */
 static int
 msg_add_rrset_ns(struct auth_zone* z, struct regional* region,
        struct dns_msg* msg, struct auth_data* node, struct auth_rrset* rrset)
@@ -1950,6 +1950,17 @@ static int auth_zone_zonemd_check_hash(struct auth_zone* z,
        return 0;
 }
 
+/** find the apex SOA RRset, if it exists */
+struct auth_rrset* auth_zone_get_soa_rrset(struct auth_zone* z)
+{
+       struct auth_data* apex;
+       struct auth_rrset* soa;
+       apex = az_find_name(z, z->name, z->namelen);
+       if(!apex) return NULL;
+       soa = az_domain_rrset(apex, LDNS_RR_TYPE_SOA);
+       return soa;
+}
+
 /** find serial number of zone or false if none */
 int
 auth_zone_get_serial(struct auth_zone* z, uint32_t* serial)
@@ -3507,7 +3518,7 @@ auth_error_encode(struct query_info* qinfo, struct module_env* env,
 
        if(!inplace_cb_reply_local_call(env, qinfo, NULL, NULL,
                rcode, edns, repinfo, temp, env->now_tv))
-               edns->opt_list = NULL;
+               edns->opt_list_inplace_cb_out = NULL;
        error_encode(buf, rcode|BIT_AA, qinfo,
                *(uint16_t*)sldns_buffer_begin(buf),
                sldns_buffer_read_u16_at(buf, 2), edns);
@@ -5347,7 +5358,9 @@ xfr_transfer_lookup_host(struct auth_xfer* xfr, struct module_env* env)
        edns.ext_rcode = 0;
        edns.edns_version = 0;
        edns.bits = EDNS_DO;
-       edns.opt_list = NULL;
+       edns.opt_list_in = NULL;
+       edns.opt_list_out = NULL;
+       edns.opt_list_inplace_cb_out = NULL;
        edns.padding_block_size = 0;
        if(sldns_buffer_capacity(buf) < 65535)
                edns.udp_size = (uint16_t)sldns_buffer_capacity(buf);
@@ -6480,7 +6493,7 @@ auth_xfer_probe_udp_callback(struct comm_point* c, void* arg, int err,
        comm_point_delete(xfr->task_probe->cp);
        xfr->task_probe->cp = NULL;
 
-       /* if the result was not a successfull probe, we need
+       /* if the result was not a successful probe, we need
         * to send the next one */
        xfr_probe_nextmaster(xfr);
        xfr_probe_send_or_end(xfr, env);
@@ -6536,7 +6549,9 @@ xfr_probe_lookup_host(struct auth_xfer* xfr, struct module_env* env)
        edns.ext_rcode = 0;
        edns.edns_version = 0;
        edns.bits = EDNS_DO;
-       edns.opt_list = NULL;
+       edns.opt_list_in = NULL;
+       edns.opt_list_out = NULL;
+       edns.opt_list_inplace_cb_out = NULL;
        edns.padding_block_size = 0;
        if(sldns_buffer_capacity(buf) < 65535)
                edns.udp_size = (uint16_t)sldns_buffer_capacity(buf);
@@ -7149,7 +7164,7 @@ parse_url(char* url, char** host, char** file, int* port, int* ssl)
        while(p && *p == '/')
                p++;
        if(!p || p[0] == 0)
-               *file = strdup("index.html");
+               *file = strdup("/");
        else    *file = strdup(p);
        if(!*file) {
                log_err("malloc failure");
@@ -7683,7 +7698,7 @@ static void auth_zone_log(uint8_t* name, enum verbosity_value level,
 static int zonemd_dnssec_verify_rrset(struct auth_zone* z,
        struct module_env* env, struct module_stack* mods,
        struct ub_packed_rrset_key* dnskey, struct auth_data* node,
-       struct auth_rrset* rrset, char** why_bogus)
+       struct auth_rrset* rrset, char** why_bogus, uint8_t* sigalg)
 {
        struct ub_packed_rrset_key pk;
        enum sec_status sec;
@@ -7711,7 +7726,7 @@ static int zonemd_dnssec_verify_rrset(struct auth_zone* z,
                auth_zone_log(z->name, VERB_ALGO,
                        "zonemd: verify %s RRset with DNSKEY", typestr);
        }
-       sec = dnskeyset_verify_rrset(env, ve, &pk, dnskey, NULL, why_bogus,
+       sec = dnskeyset_verify_rrset(env, ve, &pk, dnskey, sigalg, why_bogus,
                LDNS_SECTION_ANSWER, NULL);
        if(sec == sec_status_secure) {
                return 1;
@@ -7755,7 +7770,7 @@ static int nsec3_of_param_has_type(struct auth_rrset* nsec3, int algo,
 static int zonemd_check_dnssec_absence(struct auth_zone* z,
        struct module_env* env, struct module_stack* mods,
        struct ub_packed_rrset_key* dnskey, struct auth_data* apex,
-       char** reason, char** why_bogus)
+       char** reason, char** why_bogus, uint8_t* sigalg)
 {
        struct auth_rrset* nsec = NULL;
        if(!apex) {
@@ -7767,7 +7782,7 @@ static int zonemd_check_dnssec_absence(struct auth_zone* z,
                struct ub_packed_rrset_key pk;
                /* dnssec verify the NSEC */
                if(!zonemd_dnssec_verify_rrset(z, env, mods, dnskey, apex,
-                       nsec, why_bogus)) {
+                       nsec, why_bogus, sigalg)) {
                        *reason = "DNSSEC verify failed for NSEC RRset";
                        return 0;
                }
@@ -7810,7 +7825,7 @@ static int zonemd_check_dnssec_absence(struct auth_zone* z,
                }
                /* dnssec verify the NSEC3 */
                if(!zonemd_dnssec_verify_rrset(z, env, mods, dnskey, match,
-                       nsec3, why_bogus)) {
+                       nsec3, why_bogus, sigalg)) {
                        *reason = "DNSSEC verify failed for NSEC3 RRset";
                        return 0;
                }
@@ -7831,7 +7846,8 @@ static int zonemd_check_dnssec_absence(struct auth_zone* z,
 static int zonemd_check_dnssec_soazonemd(struct auth_zone* z,
        struct module_env* env, struct module_stack* mods,
        struct ub_packed_rrset_key* dnskey, struct auth_data* apex,
-       struct auth_rrset* zonemd_rrset, char** reason, char** why_bogus)
+       struct auth_rrset* zonemd_rrset, char** reason, char** why_bogus,
+       uint8_t* sigalg)
 {
        struct auth_rrset* soa;
        if(!apex) {
@@ -7844,12 +7860,12 @@ static int zonemd_check_dnssec_soazonemd(struct auth_zone* z,
                return 0;
        }
        if(!zonemd_dnssec_verify_rrset(z, env, mods, dnskey, apex, soa,
-               why_bogus)) {
+               why_bogus, sigalg)) {
                *reason = "DNSSEC verify failed for SOA RRset";
                return 0;
        }
        if(!zonemd_dnssec_verify_rrset(z, env, mods, dnskey, apex,
-               zonemd_rrset, why_bogus)) {
+               zonemd_rrset, why_bogus, sigalg)) {
                *reason = "DNSSEC verify failed for ZONEMD RRset";
                return 0;
        }
@@ -7908,12 +7924,14 @@ static void auth_zone_zonemd_fail(struct auth_zone* z, struct module_env* env,
  * @param is_insecure: if true, the dnskey is not used, the zone is insecure.
  *     And dnssec is not used.  It is DNSSEC secure insecure or not under
  *     a trust anchor.
+ * @param sigalg: if nonNULL provide algorithm downgrade protection.
+ *     Otherwise one algorithm is enough. Must have space of ALGO_NEEDS_MAX+1.
  * @param result: if not NULL result reason copied here.
  */
 static void
 auth_zone_verify_zonemd_with_key(struct auth_zone* z, struct module_env* env,
        struct module_stack* mods, struct ub_packed_rrset_key* dnskey,
-       int is_insecure, char** result)
+       int is_insecure, char** result, uint8_t* sigalg)
 {
        char* reason = NULL, *why_bogus = NULL;
        struct auth_data* apex = NULL;
@@ -7943,7 +7961,7 @@ auth_zone_verify_zonemd_with_key(struct auth_zone* z, struct module_env* env,
        } else if(!zonemd_rrset && dnskey && !is_insecure) {
                /* fetch, DNSSEC verify, and check NSEC/NSEC3 */
                if(!zonemd_check_dnssec_absence(z, env, mods, dnskey, apex,
-                       &reason, &why_bogus)) {
+                       &reason, &why_bogus, sigalg)) {
                        auth_zone_zonemd_fail(z, env, reason, why_bogus, result);
                        return;
                }
@@ -7951,7 +7969,7 @@ auth_zone_verify_zonemd_with_key(struct auth_zone* z, struct module_env* env,
        } else if(zonemd_rrset && dnskey && !is_insecure) {
                /* check DNSSEC verify of SOA and ZONEMD */
                if(!zonemd_check_dnssec_soazonemd(z, env, mods, dnskey, apex,
-                       zonemd_rrset, &reason, &why_bogus)) {
+                       zonemd_rrset, &reason, &why_bogus, sigalg)) {
                        auth_zone_zonemd_fail(z, env, reason, why_bogus, result);
                        return;
                }
@@ -8065,15 +8083,78 @@ zonemd_get_dnskey_from_anchor(struct auth_zone* z, struct module_env* env,
        return NULL;
 }
 
+/** verify the DNSKEY from the zone with looked up DS record */
+static struct ub_packed_rrset_key*
+auth_zone_verify_zonemd_key_with_ds(struct auth_zone* z,
+       struct module_env* env, struct module_stack* mods,
+       struct ub_packed_rrset_key* ds, int* is_insecure, char** why_bogus,
+       struct ub_packed_rrset_key* keystorage, uint8_t* sigalg)
+{
+       struct auth_data* apex;
+       struct auth_rrset* dnskey_rrset;
+       enum sec_status sec;
+       struct val_env* ve;
+       int m;
+
+       /* fetch DNSKEY from zone data */
+       apex = az_find_name(z, z->name, z->namelen);
+       if(!apex) {
+               *why_bogus = "in verifywithDS, zone has no apex";
+               return NULL;
+       }
+       dnskey_rrset = az_domain_rrset(apex, LDNS_RR_TYPE_DNSKEY);
+       if(!dnskey_rrset || dnskey_rrset->data->count==0) {
+               *why_bogus = "in verifywithDS, zone has no DNSKEY";
+               return NULL;
+       }
+
+       m = modstack_find(mods, "validator");
+       if(m == -1) {
+               *why_bogus = "in verifywithDS, have no validator module";
+               return NULL;
+       }
+       ve = (struct val_env*)env->modinfo[m];
+
+       memset(keystorage, 0, sizeof(*keystorage));
+       keystorage->entry.key = keystorage;
+       keystorage->entry.data = dnskey_rrset->data;
+       keystorage->rk.dname = apex->name;
+       keystorage->rk.dname_len = apex->namelen;
+       keystorage->rk.type = htons(LDNS_RR_TYPE_DNSKEY);
+       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);
+       regional_free_all(env->scratch);
+       if(sec == sec_status_secure) {
+               /* success */
+               return keystorage;
+       } else if(sec == sec_status_insecure) {
+               /* insecure */
+               *is_insecure = 1;
+       } else {
+               /* bogus */
+               *is_insecure = 0;
+               if(*why_bogus == NULL)
+                       *why_bogus = "verify failed";
+               auth_zone_log(z->name, VERB_ALGO,
+                       "zonemd: verify DNSKEY RRset with DS failed: %s",
+                       *why_bogus);
+       }
+       return NULL;
+}
+
 /** callback for ZONEMD lookup of DNSKEY */
 void auth_zonemd_dnskey_lookup_callback(void* arg, int rcode, sldns_buffer* buf,
        enum sec_status sec, char* why_bogus, int ATTR_UNUSED(was_ratelimited))
 {
        struct auth_zone* z = (struct auth_zone*)arg;
        struct module_env* env;
-       char* reason = NULL;
-       struct ub_packed_rrset_key* dnskey = NULL;
-       int is_insecure = 0;
+       char* reason = NULL, *ds_bogus = NULL, *typestr="DNSKEY";
+       struct ub_packed_rrset_key* dnskey = NULL, *ds = NULL;
+       int is_insecure = 0, downprot;
+       struct ub_packed_rrset_key keystorage;
+       uint8_t sigalg[ALGO_NEEDS_MAX+1];
 
        lock_rw_wrlock(&z->lock);
        env = z->zonemd_callback_env;
@@ -8084,16 +8165,22 @@ void auth_zonemd_dnskey_lookup_callback(void* arg, int rcode, sldns_buffer* buf,
                lock_rw_unlock(&z->lock);
                return; /* stop on quit */
        }
+       if(z->zonemd_callback_qtype == LDNS_RR_TYPE_DS)
+               typestr = "DS";
+       downprot = env->cfg->harden_algo_downgrade;
 
        /* process result */
        if(sec == sec_status_bogus) {
                reason = why_bogus;
-               if(!reason)
-                       reason = "lookup of DNSKEY was bogus";
+               if(!reason) {
+                       if(z->zonemd_callback_qtype == LDNS_RR_TYPE_DNSKEY)
+                               reason = "lookup of DNSKEY was bogus";
+                       else    reason = "lookup of DS was bogus";
+               }
                auth_zone_log(z->name, VERB_ALGO,
-                       "zonemd lookup of DNSKEY was bogus: %s", reason);
+                       "zonemd lookup of %s was bogus: %s", typestr, reason);
        } else if(rcode == LDNS_RCODE_NOERROR) {
-               uint16_t wanted_qtype = LDNS_RR_TYPE_DNSKEY;
+               uint16_t wanted_qtype = z->zonemd_callback_qtype;
                struct regional* temp = env->scratch;
                struct query_info rq;
                struct reply_info* rep;
@@ -8106,25 +8193,29 @@ void auth_zonemd_dnskey_lookup_callback(void* arg, int rcode, sldns_buffer* buf,
                        struct ub_packed_rrset_key* answer =
                                reply_find_answer_rrset(&rq, rep);
                        if(answer && sec == sec_status_secure) {
-                               dnskey = answer;
+                               if(z->zonemd_callback_qtype == LDNS_RR_TYPE_DNSKEY)
+                                       dnskey = answer;
+                               else    ds = answer;
                                auth_zone_log(z->name, VERB_ALGO,
-                                       "zonemd lookup of DNSKEY was secure");
+                                       "zonemd lookup of %s was secure", typestr);
                        } else if(sec == sec_status_secure && !answer) {
                                is_insecure = 1;
                                auth_zone_log(z->name, VERB_ALGO,
-                                       "zonemd lookup of DNSKEY has no content, but is secure, treat as insecure");
+                                       "zonemd lookup of %s has no content, but is secure, treat as insecure", typestr);
                        } else if(sec == sec_status_insecure) {
                                is_insecure = 1;
                                auth_zone_log(z->name, VERB_ALGO,
-                                       "zonemd lookup of DNSKEY was insecure");
+                                       "zonemd lookup of %s was insecure", typestr);
                        } else if(sec == sec_status_indeterminate) {
                                is_insecure = 1;
                                auth_zone_log(z->name, VERB_ALGO,
-                                       "zonemd lookup of DNSKEY was indeterminate, treat as insecure");
+                                       "zonemd lookup of %s was indeterminate, treat as insecure", typestr);
                        } else {
                                auth_zone_log(z->name, VERB_ALGO,
-                                       "zonemd lookup of DNSKEY has nodata");
-                               reason = "lookup of DNSKEY has nodata";
+                                       "zonemd lookup of %s has nodata", typestr);
+                               if(z->zonemd_callback_qtype == LDNS_RR_TYPE_DNSKEY)
+                                       reason = "lookup of DNSKEY has nodata";
+                               else    reason = "lookup of DS has nodata";
                        }
                } else if(rep && rq.qtype == wanted_qtype &&
                        query_dname_compare(z->name, rq.qname) == 0 &&
@@ -8137,40 +8228,52 @@ void auth_zonemd_dnskey_lookup_callback(void* arg, int rcode, sldns_buffer* buf,
                         * trust, as insecure. */
                        is_insecure = 1;
                        auth_zone_log(z->name, VERB_ALGO,
-                               "zonemd lookup of DNSKEY was secure NXDOMAIN, treat as insecure");
+                               "zonemd lookup of %s was secure NXDOMAIN, treat as insecure", typestr);
                } else if(rep && rq.qtype == wanted_qtype &&
                        query_dname_compare(z->name, rq.qname) == 0 &&
                        FLAGS_GET_RCODE(rep->flags) == LDNS_RCODE_NXDOMAIN &&
                        sec == sec_status_insecure) {
                        is_insecure = 1;
                        auth_zone_log(z->name, VERB_ALGO,
-                               "zonemd lookup of DNSKEY was insecure NXDOMAIN, treat as insecure");
+                               "zonemd lookup of %s was insecure NXDOMAIN, treat as insecure", typestr);
                } else if(rep && rq.qtype == wanted_qtype &&
                        query_dname_compare(z->name, rq.qname) == 0 &&
                        FLAGS_GET_RCODE(rep->flags) == LDNS_RCODE_NXDOMAIN &&
                        sec == sec_status_indeterminate) {
                        is_insecure = 1;
                        auth_zone_log(z->name, VERB_ALGO,
-                               "zonemd lookup of DNSKEY was indeterminate NXDOMAIN, treat as insecure");
+                               "zonemd lookup of %s was indeterminate NXDOMAIN, treat as insecure", typestr);
                } else {
                        auth_zone_log(z->name, VERB_ALGO,
-                               "zonemd lookup of DNSKEY has no answer");
-                       reason = "lookup of DNSKEY has no answer";
+                               "zonemd lookup of %s has no answer", typestr);
+                       if(z->zonemd_callback_qtype == LDNS_RR_TYPE_DNSKEY)
+                               reason = "lookup of DNSKEY has no answer";
+                       else    reason = "lookup of DS has no answer";
                }
        } else {
                auth_zone_log(z->name, VERB_ALGO,
-                       "zonemd lookup of DNSKEY failed");
-               reason = "lookup of DNSKEY failed";
+                       "zonemd lookup of %s failed", typestr);
+               if(z->zonemd_callback_qtype == LDNS_RR_TYPE_DNSKEY)
+                       reason = "lookup of DNSKEY failed";
+               else    reason = "lookup of DS failed";
+       }
+
+       if(!reason && !is_insecure && !dnskey && ds) {
+               dnskey = auth_zone_verify_zonemd_key_with_ds(z, env,
+                       &env->mesh->mods, ds, &is_insecure, &ds_bogus,
+                       &keystorage, downprot?sigalg:NULL);
+               if(!dnskey && !is_insecure && !reason)
+                       reason = "DNSKEY verify with DS failed";
        }
 
        if(reason) {
-               auth_zone_zonemd_fail(z, env, reason, NULL, NULL);
+               auth_zone_zonemd_fail(z, env, reason, ds_bogus, NULL);
                lock_rw_unlock(&z->lock);
                return;
        }
 
        auth_zone_verify_zonemd_with_key(z, env, &env->mesh->mods, dnskey,
-               is_insecure, NULL);
+               is_insecure, NULL, downprot?sigalg:NULL);
        regional_free_all(env->scratch);
        lock_rw_unlock(&z->lock);
 }
@@ -8183,14 +8286,21 @@ zonemd_lookup_dnskey(struct auth_zone* z, struct module_env* env)
        uint16_t qflags = BIT_RD;
        struct edns_data edns;
        sldns_buffer* buf = env->scratch_buffer;
+       int fetch_ds = 0;
 
+       if(!z->fallback_enabled) {
+               /* we cannot actually get the DNSKEY, because it is in the
+                * zone we have ourselves, and it is not served yet
+                * (possibly), so fetch type DS */
+               fetch_ds = 1;
+       }
        if(z->zonemd_callback_env) {
                /* another worker is already working on the callback
                 * for the DNSKEY lookup for ZONEMD verification.
                 * We do not also have to do ZONEMD verification, let that
                 * worker do it */
                auth_zone_log(z->name, VERB_ALGO,
-                       "zonemd needs lookup of DNSKEY and that already worked on by another worker");
+                       "zonemd needs lookup of %s and that already is worked on by another worker", (fetch_ds?"DS":"DNSKEY"));
                return 1;
        }
 
@@ -8199,21 +8309,26 @@ zonemd_lookup_dnskey(struct auth_zone* z, struct module_env* env)
        qinfo.qname_len = z->namelen;
        qinfo.qname = z->name;
        qinfo.qclass = z->dclass;
-       qinfo.qtype = LDNS_RR_TYPE_DNSKEY;
+       if(fetch_ds)
+               qinfo.qtype = LDNS_RR_TYPE_DS;
+       else    qinfo.qtype = LDNS_RR_TYPE_DNSKEY;
        qinfo.local_alias = NULL;
        if(verbosity >= VERB_ALGO) {
                char buf1[512];
                char buf2[LDNS_MAX_DOMAINLEN+1];
                dname_str(z->name, buf2);
-               snprintf(buf1, sizeof(buf1), "auth zone %s: lookup DNSKEY "
-                       "for zonemd verification", buf2);
+               snprintf(buf1, sizeof(buf1), "auth zone %s: lookup %s "
+                       "for zonemd verification", buf2,
+                       (fetch_ds?"DS":"DNSKEY"));
                log_query_info(VERB_ALGO, buf1, &qinfo);
        }
        edns.edns_present = 1;
        edns.ext_rcode = 0;
        edns.edns_version = 0;
        edns.bits = EDNS_DO;
-       edns.opt_list = NULL;
+       edns.opt_list_in = NULL;
+       edns.opt_list_out = NULL;
+       edns.opt_list_inplace_cb_out = NULL;
        if(sldns_buffer_capacity(buf) < 65535)
                edns.udp_size = (uint16_t)sldns_buffer_capacity(buf);
        else    edns.udp_size = 65535;
@@ -8221,12 +8336,14 @@ zonemd_lookup_dnskey(struct auth_zone* z, struct module_env* env)
        /* store the worker-specific module env for the callback.
         * We can then reference this when the callback executes */
        z->zonemd_callback_env = env;
+       z->zonemd_callback_qtype = qinfo.qtype;
        /* the callback can be called straight away */
        lock_rw_unlock(&z->lock);
        if(!mesh_new_callback(env->mesh, &qinfo, qflags, &edns, buf, 0,
                &auth_zonemd_dnskey_lookup_callback, z)) {
                lock_rw_wrlock(&z->lock);
-               log_err("out of memory lookup up dnskey for zonemd");
+               log_err("out of memory lookup of %s for zonemd",
+                       (fetch_ds?"DS":"DNSKEY"));
                return 0;
        }
        lock_rw_wrlock(&z->lock);
@@ -8245,6 +8362,8 @@ void auth_zone_verify_zonemd(struct auth_zone* z, struct module_env* env,
         * If not present check if absence is allowed by DNSSEC */
        if(!z->zonemd_check)
                return;
+       if(z->data.count == 0)
+               return; /* no data */
 
        /* if zone is under a trustanchor */
        /* is it equal to trustanchor - get dnskey's verified */
@@ -8298,7 +8417,7 @@ void auth_zone_verify_zonemd(struct auth_zone* z, struct module_env* env,
        }
 
        auth_zone_verify_zonemd_with_key(z, env, mods, dnskey, is_insecure,
-               result);
+               result, NULL);
        regional_free_all(env->scratch);
 }
 
index ffe234d..d24e569 100644 (file)
@@ -143,6 +143,8 @@ struct auth_zone {
         * worker has already picked up the zonemd verification task and
         * this worker does not have to do it as well. */
        struct module_env* zonemd_callback_env;
+       /** for the zonemd callback, the type of data looked up */
+       uint16_t zonemd_callback_qtype;
        /** zone has been deleted */
        int zone_deleted;
        /** deletelist pointer, unused normally except during delete */
@@ -634,6 +636,9 @@ int auth_zones_startprobesequence(struct auth_zones* az,
 /** read auth zone from zonefile. caller must lock zone. false on failure */
 int auth_zone_read_zonefile(struct auth_zone* z, struct config_file* cfg);
 
+/** find the apex SOA RRset, if it exists. NULL if no SOA RRset. */
+struct auth_rrset* auth_zone_get_soa_rrset(struct auth_zone* z);
+
 /** find serial number of zone or false if none (no SOA record) */
 int auth_zone_get_serial(struct auth_zone* z, uint32_t* serial);
 
index 518e696..252e1e2 100644 (file)
@@ -898,8 +898,9 @@ static void infra_ip_create_ratedata(struct infra_cache* infra,
        slabhash_insert(infra->client_ip_rates, h, &k->entry, d, NULL);
 }
 
-/** find the second and return its rate counter, if none, remove oldest */
-static int* infra_rate_find_second(void* data, time_t t)
+/** Find the second and return its rate counter. If none and should_add, remove
+ *  oldest to accommodate. Else return none. */
+static int* infra_rate_find_second_or_none(void* data, time_t t, int should_add)
 {
        struct rate_data* d = (struct rate_data*)data;
        int i, oldest;
@@ -907,6 +908,7 @@ static int* infra_rate_find_second(void* data, time_t t)
                if(d->timestamp[i] == t)
                        return &(d->qps[i]);
        }
+       if(!should_add) return NULL;
        /* remove oldest timestamp, and insert it at t with 0 qps */
        oldest = 0;
        for(i=0; i<RATE_WINDOW; i++) {
@@ -918,21 +920,41 @@ static int* infra_rate_find_second(void* data, time_t t)
        return &(d->qps[oldest]);
 }
 
-int infra_rate_max(void* data, time_t now)
+/** find the second and return its rate counter, if none, remove oldest to
+ *  accommodate */
+static int* infra_rate_give_second(void* data, time_t t)
+{
+    return infra_rate_find_second_or_none(data, t, 1);
+}
+
+/** find the second and return its rate counter only if it exists. Caller
+ *  should check for NULL return value */
+static int* infra_rate_get_second(void* data, time_t t)
+{
+    return infra_rate_find_second_or_none(data, t, 0);
+}
+
+int infra_rate_max(void* data, time_t now, int backoff)
 {
        struct rate_data* d = (struct rate_data*)data;
        int i, max = 0;
        for(i=0; i<RATE_WINDOW; i++) {
-               if(now-d->timestamp[i] <= RATE_WINDOW) {
-                       if(d->qps[i] > max)
+               if(backoff) {
+                       if(now-d->timestamp[i] <= RATE_WINDOW &&
+                               d->qps[i] > max) {
                                max = d->qps[i];
+                       }
+               } else {
+                       if(now == d->timestamp[i]) {
+                               return d->qps[i];
+                       }
                }
        }
        return max;
 }
 
 int infra_ratelimit_inc(struct infra_cache* infra, uint8_t* name,
-       size_t namelen, time_t timenow, struct query_info* qinfo,
+       size_t namelen, time_t timenow, int backoff, struct query_info* qinfo,
        struct comm_reply* replylist)
 {
        int lim, max;
@@ -949,13 +971,13 @@ int infra_ratelimit_inc(struct infra_cache* infra, uint8_t* name,
        /* find or insert ratedata */
        entry = infra_find_ratedata(infra, name, namelen, 1);
        if(entry) {
-               int premax = infra_rate_max(entry->data, timenow);
-               int* cur = infra_rate_find_second(entry->data, timenow);
+               int premax = infra_rate_max(entry->data, timenow, backoff);
+               int* cur = infra_rate_give_second(entry->data, timenow);
                (*cur)++;
-               max = infra_rate_max(entry->data, timenow);
+               max = infra_rate_max(entry->data, timenow, backoff);
                lock_rw_unlock(&entry->lock);
 
-               if(premax < lim && max >= lim) {
+               if(premax <= lim && max > lim) {
                        char buf[257], qnm[257], ts[12], cs[12], ip[128];
                        dname_str(name, buf);
                        dname_str(qinfo->qname, qnm);
@@ -970,12 +992,12 @@ int infra_ratelimit_inc(struct infra_cache* infra, uint8_t* name,
                                verbose(VERB_OPS, "ratelimit exceeded %s %d query %s %s %s", buf, lim, qnm, cs, ts);
                        }
                }
-               return (max < lim);
+               return (max <= lim);
        }
 
        /* create */
        infra_create_ratedata(infra, name, namelen, timenow);
-       return (1 < lim);
+       return (1 <= lim);
 }
 
 void infra_ratelimit_dec(struct infra_cache* infra, uint8_t* name,
@@ -987,14 +1009,19 @@ void infra_ratelimit_dec(struct infra_cache* infra, uint8_t* name,
                return; /* not enabled */
        entry = infra_find_ratedata(infra, name, namelen, 1);
        if(!entry) return; /* not cached */
-       cur = infra_rate_find_second(entry->data, timenow);
+       cur = infra_rate_get_second(entry->data, timenow);
+       if(cur == NULL) {
+               /* our timenow is not available anymore; nothing to decrease */
+               lock_rw_unlock(&entry->lock);
+               return;
+       }
        if((*cur) > 0)
                (*cur)--;
        lock_rw_unlock(&entry->lock);
 }
 
 int infra_ratelimit_exceeded(struct infra_cache* infra, uint8_t* name,
-       size_t namelen, time_t timenow)
+       size_t namelen, time_t timenow, int backoff)
 {
        struct lruhash_entry* entry;
        int lim, max;
@@ -1010,7 +1037,7 @@ int infra_ratelimit_exceeded(struct infra_cache* infra, uint8_t* name,
        entry = infra_find_ratedata(infra, name, namelen, 0);
        if(!entry)
                return 0; /* not cached */
-       max = infra_rate_max(entry->data, timenow);
+       max = infra_rate_max(entry->data, timenow, backoff);
        lock_rw_unlock(&entry->lock);
 
        return (max >= lim);
@@ -1027,7 +1054,8 @@ infra_get_mem(struct infra_cache* infra)
 }
 
 int infra_ip_ratelimit_inc(struct infra_cache* infra,
-  struct comm_reply* repinfo, time_t timenow, struct sldns_buffer* buffer)
+       struct comm_reply* repinfo, time_t timenow, int backoff,
+       struct sldns_buffer* buffer)
 {
        int max;
        struct lruhash_entry* entry;
@@ -1039,10 +1067,10 @@ int infra_ip_ratelimit_inc(struct infra_cache* infra,
        /* find or insert ratedata */
        entry = infra_find_ip_ratedata(infra, repinfo, 1);
        if(entry) {
-               int premax = infra_rate_max(entry->data, timenow);
-               int* cur = infra_rate_find_second(entry->data, timenow);
+               int premax = infra_rate_max(entry->data, timenow, backoff);
+               int* cur = infra_rate_give_second(entry->data, timenow);
                (*cur)++;
-               max = infra_rate_max(entry->data, timenow);
+               max = infra_rate_max(entry->data, timenow, backoff);
                lock_rw_unlock(&entry->lock);
 
                if(premax < infra_ip_ratelimit && max >= infra_ip_ratelimit) {
index 14f97c4..6a2371a 100644 (file)
@@ -368,6 +368,7 @@ long long infra_get_host_rto(struct infra_cache* infra,
  * @param name: zone name
  * @param namelen: zone name length
  * @param timenow: what time it is now.
+ * @param backoff: if backoff is enabled.
  * @param qinfo: for logging, query name.
  * @param replylist: for logging, querier's address (if any).
  * @return 1 if it could be incremented. 0 if the increment overshot the
@@ -375,7 +376,7 @@ long long infra_get_host_rto(struct infra_cache* infra,
  * Failures like alloc failures are not returned (probably as 1).
  */
 int infra_ratelimit_inc(struct infra_cache* infra, uint8_t* name,
-       size_t namelen, time_t timenow, struct query_info* qinfo,
+       size_t namelen, time_t timenow, int backoff, struct query_info* qinfo,
        struct comm_reply* replylist);
 
 /**
@@ -398,13 +399,15 @@ void infra_ratelimit_dec(struct infra_cache* infra, uint8_t* name,
  * @param name: zone name
  * @param namelen: zone name length
  * @param timenow: what time it is now.
+ * @param backoff: if backoff is enabled.
  * @return true if exceeded.
  */
 int infra_ratelimit_exceeded(struct infra_cache* infra, uint8_t* name,
-       size_t namelen, time_t timenow);
+       size_t namelen, time_t timenow, int backoff);
 
-/** find the maximum rate stored, not too old. 0 if no information. */
-int infra_rate_max(void* data, time_t now);
+/** find the maximum rate stored. 0 if no information.
+ *  When backoff is enabled look for the maximum in the whole RATE_WINDOW. */
+int infra_rate_max(void* data, time_t now, int backoff);
 
 /** find the ratelimit in qps for a domain. 0 if no limit for domain. */
 int infra_find_ratelimit(struct infra_cache* infra, uint8_t* name,
@@ -415,11 +418,12 @@ int infra_find_ratelimit(struct infra_cache* infra, uint8_t* name,
  *  @param infra: infra cache
  *  @param repinfo: information about client
  *  @param timenow: what time it is now.
+ *  @param backoff: if backoff is enabled.
  *  @param buffer: with query for logging.
  *  @return 1 if it could be incremented. 0 if the increment overshot the
  *  ratelimit and the query should be dropped. */
 int infra_ip_ratelimit_inc(struct infra_cache* infra,
-       struct comm_reply* repinfo, time_t timenow,
+       struct comm_reply* repinfo, time_t timenow, int backoff,
        struct sldns_buffer* buffer);
 
 /**
index 35a0d73..7c36d40 100644 (file)
@@ -120,7 +120,7 @@ void rrset_cache_touch(struct rrset_cache* r, struct ub_packed_rrset_key* key,
  *     the new rrset. The reference may be changed if the cached rrset is
  *     superior.
  *     Before calling the rrset is presumed newly allocated and changeable.
- *     Afer calling you do not hold a lock, and the rrset is inserted in
+ *     After calling you do not hold a lock, and the rrset is inserted in
  *     the hashtable so you need a lock to change it.
  * @param alloc: how to allocate (and deallocate) the special rrset key.
  * @param timenow: current time (to see if ttl in cache is expired).
@@ -143,7 +143,7 @@ int rrset_cache_update(struct rrset_cache* r, struct rrset_ref* ref,
  * @param rrset: which rrset to cache as wildcard. This rrset is left 
  *     untouched.
  * @param ce: the closest encloser, will be uses to generate the wildcard dname.
- * @param ce_len: the closest encloser lenght.
+ * @param ce_len: the closest encloser length.
  * @param alloc: how to allocate (and deallocate) the special rrset key.
  * @param timenow: current time (to see if ttl in cache is expired).
  */
index b43def5..983b96f 100644 (file)
@@ -869,9 +869,14 @@ set_ip_dscp(int socket, int addrfamily, int dscp)
        ds = dscp << 2;
        switch(addrfamily) {
        case AF_INET6:
-               if(setsockopt(socket, IPPROTO_IPV6, IPV6_TCLASS, (void*)&ds, sizeof(ds)) < 0)
+       #ifdef IPV6_TCLASS
+               if(setsockopt(socket, IPPROTO_IPV6, IPV6_TCLASS, (void*)&ds,
+                       sizeof(ds)) < 0)
                        return sock_strerror(errno);
                break;
+       #else
+               return "IPV6_TCLASS not defined on this system";
+       #endif
        default:
                if(setsockopt(socket, IPPROTO_IP, IP_TOS, (void*)&ds, sizeof(ds)) < 0)
                        return sock_strerror(errno);
@@ -1306,6 +1311,38 @@ listen_cp_insert(struct comm_point* c, struct listen_dnsport* front)
        return 1;
 }
 
+void listen_setup_locks(void)
+{
+       if(!stream_wait_lock_inited) {
+               lock_basic_init(&stream_wait_count_lock);
+               stream_wait_lock_inited = 1;
+       }
+       if(!http2_query_buffer_lock_inited) {
+               lock_basic_init(&http2_query_buffer_count_lock);
+               http2_query_buffer_lock_inited = 1;
+       }
+       if(!http2_response_buffer_lock_inited) {
+               lock_basic_init(&http2_response_buffer_count_lock);
+               http2_response_buffer_lock_inited = 1;
+       }
+}
+
+void listen_desetup_locks(void)
+{
+       if(stream_wait_lock_inited) {
+               stream_wait_lock_inited = 0;
+               lock_basic_destroy(&stream_wait_count_lock);
+       }
+       if(http2_query_buffer_lock_inited) {
+               http2_query_buffer_lock_inited = 0;
+               lock_basic_destroy(&http2_query_buffer_count_lock);
+       }
+       if(http2_response_buffer_lock_inited) {
+               http2_response_buffer_lock_inited = 0;
+               lock_basic_destroy(&http2_response_buffer_count_lock);
+       }
+}
+
 struct listen_dnsport* 
 listen_create(struct comm_base* base, struct listen_port* ports,
        size_t bufsize, int tcp_accept_count, int tcp_idle_timeout,
@@ -1327,57 +1364,44 @@ listen_create(struct comm_base* base, struct listen_port* ports,
                free(front);
                return NULL;
        }
-       if(!stream_wait_lock_inited) {
-               lock_basic_init(&stream_wait_count_lock);
-               stream_wait_lock_inited = 1;
-       }
-       if(!http2_query_buffer_lock_inited) {
-               lock_basic_init(&http2_query_buffer_count_lock);
-               http2_query_buffer_lock_inited = 1;
-       }
-       if(!http2_response_buffer_lock_inited) {
-               lock_basic_init(&http2_response_buffer_count_lock);
-               http2_response_buffer_lock_inited = 1;
-       }
 
        /* create comm points as needed */
        while(ports) {
                struct comm_point* cp = NULL;
                if(ports->ftype == listen_type_udp ||
                   ports->ftype == listen_type_udp_dnscrypt)
-                       cp = comm_point_create_udp(base, ports->fd, 
+                       cp = comm_point_create_udp(base, ports->fd,
                                front->udp_buff, cb, cb_arg, ports->socket);
                else if(ports->ftype == listen_type_tcp ||
                                ports->ftype == listen_type_tcp_dnscrypt)
-                       cp = comm_point_create_tcp(base, ports->fd, 
+                       cp = comm_point_create_tcp(base, ports->fd,
                                tcp_accept_count, tcp_idle_timeout,
                                harden_large_queries, 0, NULL,
                                tcp_conn_limit, bufsize, front->udp_buff,
                                ports->ftype, cb, cb_arg, ports->socket);
                else if(ports->ftype == listen_type_ssl ||
                        ports->ftype == listen_type_http) {
-                       cp = comm_point_create_tcp(base, ports->fd, 
+                       cp = comm_point_create_tcp(base, ports->fd,
                                tcp_accept_count, tcp_idle_timeout,
                                harden_large_queries,
                                http_max_streams, http_endpoint,
                                tcp_conn_limit, bufsize, front->udp_buff,
                                ports->ftype, cb, cb_arg, ports->socket);
-                       if(http_notls && ports->ftype == listen_type_http)
-                               cp->ssl = NULL;
-                       else
-                               cp->ssl = sslctx;
                        if(ports->ftype == listen_type_http) {
                                if(!sslctx && !http_notls) {
-                                 log_warn("HTTPS port configured, but no TLS "
-                                       "tls-service-key or tls-service-pem "
-                                       "set");
+                                       log_warn("HTTPS port configured, but "
+                                               "no TLS tls-service-key or "
+                                               "tls-service-pem set");
                                }
 #ifndef HAVE_SSL_CTX_SET_ALPN_SELECT_CB
-                               if(!http_notls)
-                                 log_warn("Unbound is not compiled with an "
-                                       "OpenSSL version supporting ALPN "
-                                       " (OpenSSL >= 1.0.2). This is required "
-                                       "to use DNS-over-HTTPS");
+                               if(!http_notls) {
+                                       log_warn("Unbound is not compiled "
+                                               "with an OpenSSL version "
+                                               "supporting ALPN "
+                                               "(OpenSSL >= 1.0.2). This "
+                                               "is required to use "
+                                               "DNS-over-HTTPS");
+                               }
 #endif
 #ifndef HAVE_NGHTTP2_NGHTTP2_H
                                log_warn("Unbound is not compiled with "
@@ -1387,13 +1411,17 @@ listen_create(struct comm_base* base, struct listen_port* ports,
                        }
                } else if(ports->ftype == listen_type_udpancil ||
                                  ports->ftype == listen_type_udpancil_dnscrypt)
-                       cp = comm_point_create_udp_ancil(base, ports->fd, 
+                       cp = comm_point_create_udp_ancil(base, ports->fd,
                                front->udp_buff, cb, cb_arg, ports->socket);
                if(!cp) {
-                       log_err("can't create commpoint");      
+                       log_err("can't create commpoint");
                        listen_delete(front);
                        return NULL;
                }
+               if(http_notls && ports->ftype == listen_type_http)
+                       cp->ssl = NULL;
+               else
+                       cp->ssl = sslctx;
                cp->dtenv = dtenv;
                cp->do_not_close = 1;
 #ifdef USE_DNSCRYPT
@@ -1454,18 +1482,6 @@ listen_delete(struct listen_dnsport* front)
 #endif
        sldns_buffer_free(front->udp_buff);
        free(front);
-       if(stream_wait_lock_inited) {
-               stream_wait_lock_inited = 0;
-               lock_basic_destroy(&stream_wait_count_lock);
-       }
-       if(http2_query_buffer_lock_inited) {
-               http2_query_buffer_lock_inited = 0;
-               lock_basic_destroy(&http2_query_buffer_count_lock);
-       }
-       if(http2_response_buffer_lock_inited) {
-               http2_response_buffer_lock_inited = 0;
-               lock_basic_destroy(&http2_response_buffer_count_lock);
-       }
 }
 
 #ifdef HAVE_GETIFADDRS
@@ -2610,7 +2626,7 @@ static int http2_req_begin_headers_cb(nghttp2_session* session,
        int ret;
        if(frame->hd.type != NGHTTP2_HEADERS ||
                frame->headers.cat != NGHTTP2_HCAT_REQUEST) {
-               /* only interrested in request headers */
+               /* only interested in request headers */
                return 0;
        }
        if(!(h2_stream = http2_stream_create(frame->hd.stream_id))) {
@@ -2738,7 +2754,7 @@ static int http2_req_header_cb(nghttp2_session* session,
         * the HEADER */
        if(frame->hd.type != NGHTTP2_HEADERS ||
                frame->headers.cat != NGHTTP2_HCAT_REQUEST) {
-               /* only interrested in request headers */
+               /* only interested in request headers */
                return 0;
        }
        if(!(h2_stream = nghttp2_session_get_stream_user_data(session,
@@ -2834,7 +2850,7 @@ static int http2_req_header_cb(nghttp2_session* session,
                        h2_stream->query_too_large = 1;
                        return 0;
                }
-               /* guaranteed to only contian digits and be null terminated */
+               /* guaranteed to only contain digits and be null terminated */
                h2_stream->content_length = atoi((const char*)value);
                if(h2_stream->content_length >
                        h2_session->c->http2_stream_max_qbuffer_size) {
@@ -2874,7 +2890,7 @@ static int http2_req_data_chunk_recv_cb(nghttp2_session* ATTR_UNUSED(session),
                        /* setting this to msg-buffer-size can result in a lot
                         * of memory consuption. Most queries should fit in a
                         * single DATA frame, and most POST queries will
-                        * containt content-length which does not impose this
+                        * contain content-length which does not impose this
                         * limit. */
                        qlen = len;
                }
index 1e51be9..0e63236 100644 (file)
@@ -199,6 +199,11 @@ listen_create(struct comm_base* base, struct listen_port* ports,
  */
 void listen_delete(struct listen_dnsport* listen);
 
+/** setup the locks for the listen ports */
+void listen_setup_locks(void);
+/** desetup the locks for the listen ports */
+void listen_desetup_locks(void);
+
 /**
  * delete listen_list of commpoints. Calls commpointdelete() on items.
  * This may close the fds or not depending on flags.
index 54f55ab..3e3a71a 100644 (file)
  * with 16 bytes for an A record, a 64K packet has about 4000 max */
 #define LOCALZONE_RRSET_COUNT_MAX 4096
 
+/** print all RRsets in local zone */
+static void
+local_zone_out(struct local_zone* z)
+{
+       struct local_data* d;
+       struct local_rrset* p;
+       RBTREE_FOR(d, struct local_data*, &z->data) {
+               for(p = d->rrsets; p; p = p->next) {
+                       log_nametypeclass(NO_VERBOSE, "rrset", d->name,
+                               ntohs(p->rrset->rk.type),
+                               ntohs(p->rrset->rk.rrset_class));
+               }
+       }
+}
+
+static void
+local_zone_print(struct local_zone* z)
+{
+       char buf[64];
+       lock_rw_rdlock(&z->lock);
+       snprintf(buf, sizeof(buf), "%s zone",
+               local_zone_type2str(z->type));
+       log_nametypeclass(NO_VERBOSE, buf, z->name, 0, z->dclass);
+       local_zone_out(z);
+       lock_rw_unlock(&z->lock);
+}
+
+void local_zones_print(struct local_zones* zones)
+{
+       struct local_zone* z;
+       lock_rw_rdlock(&zones->lock);
+       log_info("number of auth zones %u", (unsigned)zones->ztree.count);
+       RBTREE_FOR(z, struct local_zone*, &zones->ztree) {
+               local_zone_print(z);
+       }
+       lock_rw_unlock(&zones->lock);
+}
+
 struct local_zones* 
 local_zones_create(void)
 {
@@ -465,7 +503,7 @@ lz_find_create_node(struct local_zone* z, uint8_t* nm, size_t nmlen,
 
 /* Mark the SOA record for the zone. This only marks the SOA rrset; the data
  * for the RR is entered later on local_zone_enter_rr() as with the other
- * records. An artifical soa_negative record with a modified TTL (minimum of
+ * records. An artificial soa_negative record with a modified TTL (minimum of
  * the TTL and the SOA.MINIMUM) is also created and marked for usage with
  * negative answers and to avoid allocations during those answers. */
 static int
@@ -898,6 +936,11 @@ int local_zone_enter_defaults(struct local_zones* zones, struct config_file* cfg
                }
                lock_rw_unlock(&z->lock);
        }
+       /* home.arpa. zone (RFC 8375) */
+       if(!add_empty_default(zones, cfg, "home.arpa.")) {
+               log_err("out of memory adding default zone");
+               return 0;
+       }
        /* onion. zone (RFC 7686) */
        if(!add_empty_default(zones, cfg, "onion.")) {
                log_err("out of memory adding default zone");
@@ -1005,6 +1048,38 @@ lz_setup_implicit(struct local_zones* zones, struct config_file* cfg)
                lock_rw_rdlock(&zones->lock);
                if(!local_zones_lookup(zones, rr_name, len, labs, rr_class,
                        rr_type)) {
+                       /* Check if there is a zone that this could go
+                        * under but for different class; created zones are
+                        * always for LDNS_RR_CLASS_IN. Create the zone with
+                        * a different class but the same configured
+                        * local_zone_type. */
+                       struct local_zone* z = local_zones_lookup(zones,
+                               rr_name, len, labs, LDNS_RR_CLASS_IN, rr_type);
+                       if(z) {
+                               uint8_t* name = memdup(z->name, z->namelen);
+                               size_t znamelen = z->namelen;
+                               int znamelabs = z->namelabs;
+                               enum localzone_type ztype = z->type;
+                               lock_rw_unlock(&zones->lock);
+                               if(!name) {
+                                       log_err("out of memory");
+                                       free(rr_name);
+                                       return 0;
+                               }
+                               if(!(
+#ifndef THREADS_DISABLED
+                                       z =
+#endif
+                                       lz_enter_zone_dname(zones, name,
+                                               znamelen, znamelabs,
+                                               ztype, rr_class))) {
+                                       free(rr_name);
+                                       return 0;
+                               }
+                               lock_rw_unlock(&z->lock);
+                               free(rr_name);
+                               continue;
+                       }
                        if(!have_name) {
                                dclass = rr_class;
                                nm = rr_name;
@@ -1215,38 +1290,6 @@ local_zones_find_le(struct local_zones* zones,
        return (struct local_zone*)node;
 }
 
-/** print all RRsets in local zone */
-static void 
-local_zone_out(struct local_zone* z)
-{
-       struct local_data* d;
-       struct local_rrset* p;
-       RBTREE_FOR(d, struct local_data*, &z->data) {
-               for(p = d->rrsets; p; p = p->next) {
-                       log_nametypeclass(NO_VERBOSE, "rrset", d->name,
-                               ntohs(p->rrset->rk.type),
-                               ntohs(p->rrset->rk.rrset_class));
-               }
-       }
-}
-
-void local_zones_print(struct local_zones* zones)
-{
-       struct local_zone* z;
-       lock_rw_rdlock(&zones->lock);
-       log_info("number of auth zones %u", (unsigned)zones->ztree.count);
-       RBTREE_FOR(z, struct local_zone*, &zones->ztree) {
-               char buf[64];
-               lock_rw_rdlock(&z->lock);
-               snprintf(buf, sizeof(buf), "%s zone",
-                       local_zone_type2str(z->type));
-               log_nametypeclass(NO_VERBOSE, buf, z->name, 0, z->dclass);
-               local_zone_out(z);
-               lock_rw_unlock(&z->lock);
-       }
-       lock_rw_unlock(&zones->lock);
-}
-
 /** encode answer consisting of 1 rrset */
 static int
 local_encode(struct query_info* qinfo, struct module_env* env,
@@ -1294,7 +1337,7 @@ local_error_encode(struct query_info* qinfo, struct module_env* env,
 
        if(!inplace_cb_reply_local_call(env, qinfo, NULL, NULL,
                rcode, edns, repinfo, temp, env->now_tv))
-               edns->opt_list = NULL;
+               edns->opt_list_inplace_cb_out = NULL;
        error_encode(buf, r, qinfo, *(uint16_t*)sldns_buffer_begin(buf),
                sldns_buffer_read_u16_at(buf, 2), edns);
 }
@@ -1521,7 +1564,7 @@ local_data_answer(struct local_zone* z, struct module_env* env,
                        /* write qname */
                        memmove(d->rr_data[0] + sizeof(uint16_t), qinfo->qname,
                                qinfo->qname_len - 1);
-                       /* write cname target wilcard wildcard label */
+                       /* write cname target wildcard label */
                        memmove(d->rr_data[0] + sizeof(uint16_t) +
                                qinfo->qname_len - 1, ctarget + 2,
                                ctargetlen - 2);
@@ -1570,6 +1613,15 @@ local_zone_does_not_cover(struct local_zone* z, struct query_info* qinfo,
        return (lr == NULL);
 }
 
+static inline int
+local_zone_is_udp_query(struct comm_reply* repinfo) {
+       return repinfo != NULL
+                       ? (repinfo->c != NULL
+                               ? repinfo->c->type == comm_udp
+                               : 0)
+                       : 0;
+}
+
 int
 local_zones_zone_answer(struct local_zone* z, struct module_env* env,
        struct query_info* qinfo, struct edns_data* edns,
@@ -1592,7 +1644,9 @@ local_zones_zone_answer(struct local_zone* z, struct module_env* env,
                lz_type == local_zone_redirect ||
                lz_type == local_zone_inform_redirect ||
                lz_type == local_zone_always_nxdomain ||
-               lz_type == local_zone_always_nodata) {
+               lz_type == local_zone_always_nodata ||
+               (lz_type == local_zone_truncate
+                       && local_zone_is_udp_query(repinfo))) {
                /* for static, reply nodata or nxdomain
                 * for redirect, reply nodata */
                /* no additional section processing,
@@ -1602,9 +1656,11 @@ local_zones_zone_answer(struct local_zone* z, struct module_env* env,
                 */
                int rcode = (ld || lz_type == local_zone_redirect ||
                        lz_type == local_zone_inform_redirect ||
-                       lz_type == local_zone_always_nodata)?
+                       lz_type == local_zone_always_nodata ||
+                       lz_type == local_zone_truncate)?
                        LDNS_RCODE_NOERROR:LDNS_RCODE_NXDOMAIN;
-               if(z->soa && z->soa_negative)
+               rcode = (lz_type == local_zone_truncate ? (rcode|BIT_TC) : rcode);
+               if(z != NULL && z->soa && z->soa_negative)
                        return local_encode(qinfo, env, edns, repinfo, buf, temp,
                                z->soa_negative, 0, rcode);
                local_error_encode(qinfo, env, edns, repinfo, buf, temp, rcode,
@@ -1661,7 +1717,7 @@ local_zones_zone_answer(struct local_zone* z, struct module_env* env,
         * does not, then we should make this noerror/nodata */
        if(ld && ld->rrsets) {
                int rcode = LDNS_RCODE_NOERROR;
-               if(z->soa && z->soa_negative)
+               if(z != NULL && z->soa && z->soa_negative)
                        return local_encode(qinfo, env, edns, repinfo, buf, temp,
                                z->soa_negative, 0, rcode);
                local_error_encode(qinfo, env, edns, repinfo, buf, temp, rcode,
@@ -1860,6 +1916,7 @@ const char* local_zone_type2str(enum localzone_type t)
                case local_zone_always_deny: return "always_deny";
                case local_zone_always_null: return "always_null";
                case local_zone_noview: return "noview";
+               case local_zone_truncate: return "truncate";
                case local_zone_invalid: return "invalid";
        }
        return "badtyped"; 
@@ -1899,6 +1956,8 @@ int local_zone_str2type(const char* type, enum localzone_type* t)
                *t = local_zone_always_null;
        else if(strcmp(type, "noview") == 0)
                *t = local_zone_noview;
+       else if(strcmp(type, "truncate") == 0)
+               *t = local_zone_truncate;
        else if(strcmp(type, "nodefault") == 0)
                *t = local_zone_nodefault;
        else return 0;
index b52d81d..19534f7 100644 (file)
@@ -101,6 +101,8 @@ enum localzone_type {
        local_zone_always_null,
        /** answer not from the view, but global or no-answer */
        local_zone_noview,
+       /** truncate the response; client should retry via tcp */
+       local_zone_truncate,
        /** Invalid type, cannot be used to generate answer */
        local_zone_invalid
 };
@@ -255,7 +257,7 @@ void local_zone_delete(struct local_zone* z);
  * @param dclass: class to lookup.
  * @param dtype: type to lookup, if type DS a zone higher is used for zonecuts.
  * @param taglist: taglist to lookup.
- * @param taglen: lenth of taglist.
+ * @param taglen: length of taglist.
  * @param ignoretags: lookup zone by name and class, regardless the
  * local-zone's tags.
  * @return closest local_zone or NULL if no covering zone is found.
@@ -563,6 +565,8 @@ enum respip_action {
        respip_always_nodata = local_zone_always_nodata,
         /** answer with nodata response */
        respip_always_deny = local_zone_always_deny,
+       /** RPZ: truncate answer in order to force switch to tcp */
+       respip_truncate = local_zone_truncate,
 
        /* The rest of the values are only possible as
         * access-control-tag-action */
index 5679a8b..cdcfedd 100644 (file)
@@ -461,7 +461,7 @@ void mesh_new_client(struct mesh_area* mesh, struct query_info* qinfo,
        struct edns_data* edns, struct comm_reply* rep, uint16_t qid)
 {
        struct mesh_state* s = NULL;
-       int unique = unique_mesh_state(edns->opt_list, mesh->env);
+       int unique = unique_mesh_state(edns->opt_list_in, mesh->env);
        int was_detached = 0;
        int was_noreply = 0;
        int added = 0;
@@ -505,7 +505,7 @@ void mesh_new_client(struct mesh_area* mesh, struct query_info* qinfo,
                        log_err("mesh_state_create: out of memory; SERVFAIL");
                        if(!inplace_cb_reply_servfail_call(mesh->env, qinfo, NULL, NULL,
                                LDNS_RCODE_SERVFAIL, edns, rep, mesh->env->scratch, mesh->env->now_tv))
-                                       edns->opt_list = NULL;
+                                       edns->opt_list_inplace_cb_out = NULL;
                        error_encode(r_buffer, LDNS_RCODE_SERVFAIL,
                                qinfo, qid, qflags, edns);
                        comm_point_send_reply(rep);
@@ -514,14 +514,14 @@ void mesh_new_client(struct mesh_area* mesh, struct query_info* qinfo,
                if(unique)
                        mesh_state_make_unique(s);
                /* copy the edns options we got from the front */
-               if(edns->opt_list) {
-                       s->s.edns_opts_front_in = edns_opt_copy_region(edns->opt_list,
+               if(edns->opt_list_in) {
+                       s->s.edns_opts_front_in = edns_opt_copy_region(edns->opt_list_in,
                                s->s.region);
                        if(!s->s.edns_opts_front_in) {
                                log_err("mesh_state_create: out of memory; SERVFAIL");
                                if(!inplace_cb_reply_servfail_call(mesh->env, qinfo, NULL,
                                        NULL, LDNS_RCODE_SERVFAIL, edns, rep, mesh->env->scratch, mesh->env->now_tv))
-                                               edns->opt_list = NULL;
+                                               edns->opt_list_inplace_cb_out = NULL;
                                error_encode(r_buffer, LDNS_RCODE_SERVFAIL,
                                        qinfo, qid, qflags, edns);
                                comm_point_send_reply(rep);
@@ -594,7 +594,7 @@ void mesh_new_client(struct mesh_area* mesh, struct query_info* qinfo,
 servfail_mem:
        if(!inplace_cb_reply_servfail_call(mesh->env, qinfo, &s->s,
                NULL, LDNS_RCODE_SERVFAIL, edns, rep, mesh->env->scratch, mesh->env->now_tv))
-                       edns->opt_list = NULL;
+                       edns->opt_list_inplace_cb_out = NULL;
        error_encode(r_buffer, LDNS_RCODE_SERVFAIL,
                qinfo, qid, qflags, edns);
        comm_point_send_reply(rep);
@@ -609,7 +609,7 @@ mesh_new_callback(struct mesh_area* mesh, struct query_info* qinfo,
        uint16_t qid, mesh_cb_func_type cb, void* cb_arg)
 {
        struct mesh_state* s = NULL;
-       int unique = unique_mesh_state(edns->opt_list, mesh->env);
+       int unique = unique_mesh_state(edns->opt_list_in, mesh->env);
        int timeout = mesh->env->cfg->serve_expired?
                mesh->env->cfg->serve_expired_client_timeout:0;
        int was_detached = 0;
@@ -632,8 +632,8 @@ mesh_new_callback(struct mesh_area* mesh, struct query_info* qinfo,
                }
                if(unique)
                        mesh_state_make_unique(s);
-               if(edns->opt_list) {
-                       s->s.edns_opts_front_in = edns_opt_copy_region(edns->opt_list,
+               if(edns->opt_list_in) {
+                       s->s.edns_opts_front_in = edns_opt_copy_region(edns->opt_list_in,
                                s->s.region);
                        if(!s->s.edns_opts_front_in) {
                                return 0;
@@ -1145,11 +1145,11 @@ mesh_do_callback(struct mesh_state* m, int rcode, struct reply_info* rep,
                if(rcode == LDNS_RCODE_SERVFAIL) {
                        if(!inplace_cb_reply_servfail_call(m->s.env, &m->s.qinfo, &m->s,
                                rep, rcode, &r->edns, NULL, m->s.region, start_time))
-                                       r->edns.opt_list = NULL;
+                                       r->edns.opt_list_inplace_cb_out = NULL;
                } else {
                        if(!inplace_cb_reply_call(m->s.env, &m->s.qinfo, &m->s, rep, rcode,
                                &r->edns, NULL, m->s.region, start_time))
-                                       r->edns.opt_list = NULL;
+                                       r->edns.opt_list_inplace_cb_out = NULL;
                }
                fptr_ok(fptr_whitelist_mesh_cb(r->cb));
                (*r->cb)(r->cb_arg, rcode, r->buf, sec_status_unchecked, NULL,
@@ -1183,6 +1183,22 @@ mesh_do_callback(struct mesh_state* m, int rcode, struct reply_info* rep,
        m->s.env->mesh->num_reply_addrs--;
 }
 
+static inline int
+mesh_is_rpz_respip_tcponly_action(struct mesh_state const* m)
+{
+       struct respip_action_info const* respip_info = m->s.respip_action_info;
+       return respip_info == NULL
+                       ? 0
+                       : (respip_info->rpz_used
+                       && !respip_info->rpz_disabled
+                       && respip_info->action == respip_truncate);
+}
+
+static inline int
+mesh_is_udp(struct mesh_reply const* r) {
+       return r->query_reply.c->type == comm_udp;
+}
+
 /**
  * Send reply to mesh reply entry
  * @param m: mesh state to send it for.
@@ -1201,15 +1217,17 @@ mesh_send_reply(struct mesh_state* m, int rcode, struct reply_info* rep,
        struct timeval end_time;
        struct timeval duration;
        int secure;
-       /* Copy the client's EDNS for later restore, to make sure the edns
-        * compare is with the correct edns options. */
-       struct edns_data edns_bak = r->edns;
        /* 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)
+                       ? (rcode|BIT_TC) : rcode;
+
        /* examine security status */
        if(m->s.env->need_to_validate && (!(r->qflags&BIT_CD) ||
                m->s.env->cfg->ignore_cd) && rep && 
@@ -1248,8 +1266,9 @@ mesh_send_reply(struct mesh_state* m, int rcode, struct reply_info* rep,
                prev->edns.edns_present == r->edns.edns_present &&
                prev->edns.bits == r->edns.bits &&
                prev->edns.udp_size == r->edns.udp_size &&
-               edns_opt_list_compare(prev->edns.opt_list, r->edns.opt_list)
-               == 0) {
+               edns_opt_list_compare(prev->edns.opt_list_out, r->edns.opt_list_out) == 0 &&
+               edns_opt_list_compare(prev->edns.opt_list_inplace_cb_out, r->edns.opt_list_inplace_cb_out) == 0
+               ) {
                /* if the previous reply is identical to this one, fix ID */
                if(prev_buffer != r_buffer)
                        sldns_buffer_copy(r_buffer, prev_buffer);
@@ -1265,11 +1284,11 @@ mesh_send_reply(struct mesh_state* m, int rcode, struct reply_info* rep,
                if(rcode == LDNS_RCODE_SERVFAIL) {
                        if(!inplace_cb_reply_servfail_call(m->s.env, &m->s.qinfo, &m->s,
                                rep, rcode, &r->edns, &r->query_reply, m->s.region, &r->start_time))
-                                       r->edns.opt_list = NULL;
+                                       r->edns.opt_list_inplace_cb_out = NULL;
                } else { 
                        if(!inplace_cb_reply_call(m->s.env, &m->s.qinfo, &m->s, rep, rcode,
                                &r->edns, &r->query_reply, m->s.region, &r->start_time))
-                                       r->edns.opt_list = NULL;
+                                       r->edns.opt_list_inplace_cb_out = NULL;
                }
                error_encode(r_buffer, rcode, &m->s.qinfo, r->qid,
                        r->qflags, &r->edns);
@@ -1286,9 +1305,6 @@ mesh_send_reply(struct mesh_state* m, int rcode, struct reply_info* rep,
                m->s.qinfo.local_alias = r->local_alias;
                if(!inplace_cb_reply_call(m->s.env, &m->s.qinfo, &m->s, rep,
                        LDNS_RCODE_NOERROR, &r->edns, &r->query_reply, m->s.region, &r->start_time) ||
-                       !apply_edns_options(&r->edns, &edns_bak,
-                               m->s.env->cfg, r->query_reply.c,
-                               m->s.region) ||
                        !reply_info_answer_encode(&m->s.qinfo, rep, r->qid, 
                        r->qflags, r_buffer, 0, 1, m->s.env->scratch,
                        udp_size, &r->edns, (int)(r->edns.bits & EDNS_DO),
@@ -1296,11 +1312,10 @@ mesh_send_reply(struct mesh_state* m, int rcode, struct reply_info* rep,
                {
                        if(!inplace_cb_reply_servfail_call(m->s.env, &m->s.qinfo, &m->s,
                        rep, LDNS_RCODE_SERVFAIL, &r->edns, &r->query_reply, m->s.region, &r->start_time))
-                               r->edns.opt_list = NULL;
+                               r->edns.opt_list_inplace_cb_out = NULL;
                        error_encode(r_buffer, LDNS_RCODE_SERVFAIL,
                                &m->s.qinfo, r->qid, r->qflags, &r->edns);
                }
-               r->edns = edns_bak;
                m->reply_list = NULL;
                comm_point_send_reply(&r->query_reply);
                m->reply_list = rlist;
@@ -1346,7 +1361,7 @@ void mesh_query_done(struct mesh_state* mstate)
        }
        if(mstate->s.return_rcode == LDNS_RCODE_SERVFAIL ||
                (rep && FLAGS_GET_RCODE(rep->flags) == LDNS_RCODE_SERVFAIL)) {
-               /* we are SERVFAILing; check for expired asnwer here */
+               /* we are SERVFAILing; check for expired answer here */
                mesh_serve_expired_callback(mstate);
                if((mstate->reply_list || mstate->cb_list)
                && mstate->s.env->cfg->log_servfail
@@ -1488,12 +1503,15 @@ int mesh_state_add_cb(struct mesh_state* s, struct edns_data* edns,
        r->cb = cb;
        r->cb_arg = cb_arg;
        r->edns = *edns;
-       if(edns->opt_list) {
-               r->edns.opt_list = edns_opt_copy_region(edns->opt_list,
-                       s->s.region);
-               if(!r->edns.opt_list)
-                       return 0;
-       }
+       if(edns->opt_list_in && !(r->edns.opt_list_in =
+                       edns_opt_copy_region(edns->opt_list_in, s->s.region)))
+               return 0;
+       if(edns->opt_list_out && !(r->edns.opt_list_out =
+                       edns_opt_copy_region(edns->opt_list_out, s->s.region)))
+               return 0;
+       if(edns->opt_list_inplace_cb_out && !(r->edns.opt_list_inplace_cb_out =
+                       edns_opt_copy_region(edns->opt_list_inplace_cb_out, s->s.region)))
+               return 0;
        r->qid = qid;
        r->qflags = qflags;
        r->next = s->cb_list;
@@ -1512,12 +1530,15 @@ int mesh_state_add_reply(struct mesh_state* s, struct edns_data* edns,
                return 0;
        r->query_reply = *rep;
        r->edns = *edns;
-       if(edns->opt_list) {
-               r->edns.opt_list = edns_opt_copy_region(edns->opt_list,
-                       s->s.region);
-               if(!r->edns.opt_list)
-                       return 0;
-       }
+       if(edns->opt_list_in && !(r->edns.opt_list_in =
+                       edns_opt_copy_region(edns->opt_list_in, s->s.region)))
+               return 0;
+       if(edns->opt_list_out && !(r->edns.opt_list_out =
+                       edns_opt_copy_region(edns->opt_list_out, s->s.region)))
+               return 0;
+       if(edns->opt_list_inplace_cb_out && !(r->edns.opt_list_inplace_cb_out =
+                       edns_opt_copy_region(edns->opt_list_inplace_cb_out, s->s.region)))
+               return 0;
        r->qid = qid;
        r->qflags = qflags;
        r->start_time = *s->s.env->now_tv;
@@ -1563,7 +1584,7 @@ int mesh_state_add_reply(struct mesh_state* s, struct edns_data* edns,
                        return 0;
 
                /* the rrset is not packed, like in the cache, but it is
-                * individualy allocated with an allocator from localzone. */
+                * individually allocated with an allocator from localzone. */
                d = regional_alloc_zero(s->s.region, sizeof(*d));
                if(!d)
                        return 0;
index a3f982e..a7e5fa3 100644 (file)
@@ -94,6 +94,16 @@ static void waiting_list_remove(struct outside_network* outnet,
 static uint16_t tcp_select_id(struct outside_network* outnet,
        struct reuse_tcp* reuse);
 
+/** Perform serviced query UDP sending operation */
+static int serviced_udp_send(struct serviced_query* sq, sldns_buffer* buff);
+
+/** Send serviced query over TCP return false on initial failure */
+static int serviced_tcp_send(struct serviced_query* sq, sldns_buffer* buff);
+
+/** call the callbacks for a serviced query */
+static void serviced_callbacks(struct serviced_query* sq, int error,
+       struct comm_point* c, struct comm_reply* rep);
+
 int 
 pending_cmp(const void* key1, const void* key2)
 {
@@ -836,6 +846,7 @@ outnet_add_tcp_waiting_first(struct outside_network* outnet,
        if(w->on_tcp_waiting_list)
                return;
        w->next_waiting = outnet->tcp_wait_first;
+       log_assert(w->next_waiting != w);
        if(!outnet->tcp_wait_last)
                outnet->tcp_wait_last = w;
        outnet->tcp_wait_first = w;
@@ -1136,6 +1147,22 @@ static void reuse_cb_readwait_for_failure(rbtree_type* tree_by_id, int err)
        }
 }
 
+/** mark the entry for being in the cb_and_decommission stage */
+static void mark_for_cb_and_decommission(rbnode_type* node,
+       void* ATTR_UNUSED(arg))
+{
+       struct waiting_tcp* w = (struct waiting_tcp*)node->key;
+       /* Mark the waiting_tcp to signal later code (serviced_delete) that
+        * this item is part of the backed up tree_by_id and will be deleted
+        * later. */
+       w->in_cb_and_decommission = 1;
+       /* Mark the serviced_query for deletion so that later code through
+        * callbacks (iter_clear .. outnet_serviced_query_stop) won't
+        * prematurely delete it. */
+       if(w->cb)
+               ((struct serviced_query*)w->cb_arg)->to_be_deleted = 1;
+}
+
 /** perform callbacks for failure and also decommission pending tcp.
  * the callbacks remove references in sq->pending to the waiting_tcp
  * members of the tree_by_id in the pending tcp.  The pending_tcp is
@@ -1151,6 +1178,9 @@ static void reuse_cb_and_decommission(struct outside_network* outnet,
        pend->reuse.write_wait_first = NULL;
        pend->reuse.write_wait_last = NULL;
        decommission_pending_tcp(outnet, pend);
+       if(store.root != NULL && store.root != RBTREE_NULL) {
+               traverse_postorder(&store, &mark_for_cb_and_decommission, NULL);
+       }
        reuse_cb_readwait_for_failure(&store, error);
        reuse_del_readwait(&store);
 }
@@ -1248,6 +1278,12 @@ outnet_tcp_cb(struct comm_point* c, void* arg, int error,
                                c->buffer));
                        /* find the query the reply is for */
                        w = reuse_tcp_by_id_find(&pend->reuse, id);
+                       /* Make sure that the reply we got is at least for a
+                        * sent query with the same ID; the waiting_tcp that
+                        * gets a reply is assumed to not be waiting to be
+                        * sent. */
+                       if(w && (w->on_tcp_waiting_list || w->write_wait_queued))
+                               w = NULL;
                }
        }
        if(error == NETEVENT_NOERROR && !w) {
@@ -1265,6 +1301,8 @@ outnet_tcp_cb(struct comm_point* c, void* arg, int error,
                }
        }
        if(w) {
+               log_assert(!w->on_tcp_waiting_list);
+               log_assert(!w->write_wait_queued);
                reuse_tree_by_id_delete(&pend->reuse, w);
                verbose(VERB_CLIENT, "outnet tcp callback query err %d buflen %d",
                        error, (int)sldns_buffer_limit(c->buffer));
@@ -1324,7 +1362,7 @@ outnet_send_wait_udp(struct outside_network* outnet)
 {
        struct pending* pend;
        /* process waiting queries */
-       while(outnet->udp_wait_first && outnet->unused_fds 
+       while(outnet->udp_wait_first && outnet->unused_fds
                && !outnet->want_to_quit) {
                pend = outnet->udp_wait_first;
                outnet->udp_wait_first = pend->next_waiting;
@@ -1333,8 +1371,10 @@ outnet_send_wait_udp(struct outside_network* outnet)
                sldns_buffer_write(outnet->udp_buff, pend->pkt, pend->pkt_len);
                sldns_buffer_flip(outnet->udp_buff);
                free(pend->pkt); /* freeing now makes get_mem correct */
-               pend->pkt = NULL; 
+               pend->pkt = NULL;
                pend->pkt_len = 0;
+               log_assert(!pend->sq->busy);
+               pend->sq->busy = 1;
                if(!randomize_and_send_udp(pend, outnet->udp_buff,
                        pend->timeout)) {
                        /* callback error on pending */
@@ -1344,6 +1384,8 @@ outnet_send_wait_udp(struct outside_network* outnet)
                                        NETEVENT_CLOSED, NULL);
                        }
                        pending_delete(outnet, pend);
+               } else {
+                       pend->sq->busy = 0;
                }
        }
 }
@@ -1454,7 +1496,6 @@ calc_num46(char** ifs, int num_ifs, int do_ip4, int do_ip6,
                                (*num_ip4)++;
                }
        }
-
 }
 
 void
@@ -1708,16 +1749,9 @@ static void
 serviced_node_del(rbnode_type* node, void* ATTR_UNUSED(arg))
 {
        struct serviced_query* sq = (struct serviced_query*)node;
-       struct service_callback* p = sq->cblist, *np;
-       free(sq->qbuf);
-       free(sq->zone);
-       free(sq->tls_auth_name);
-       edns_opt_list_free(sq->opt_list);
-       while(p) {
-               np = p->next;
-               free(p);
-               p = np;
-       }
+       alloc_reg_release(sq->alloc, sq->region);
+       if(sq->timer)
+               comm_timer_delete(sq->timer);
        free(sq);
 }
 
@@ -1935,7 +1969,7 @@ select_id(struct outside_network* outnet, struct pending* pend,
                LDNS_ID_SET(sldns_buffer_begin(packet), pend->id);
                id_tries++;
                if(id_tries == MAX_ID_RETRY) {
-                       pend->id=99999; /* non existant ID */
+                       pend->id=99999; /* non existent ID */
                        log_err("failed to generate unique ID, drop msg");
                        return 0;
                }
@@ -1962,6 +1996,7 @@ static int udp_connect_needs_log(int err)
        case ENETDOWN:
 #  endif
        case EPERM:
+       case EACCES:
                if(verbosity >= VERB_ALGO)
                        return 1;
                return 0;
@@ -2173,10 +2208,13 @@ pending_udp_query(struct serviced_query* sq, struct sldns_buffer* packet,
                sq->outnet->udp_wait_last = pend;
                return pend;
        }
+       log_assert(!sq->busy);
+       sq->busy = 1;
        if(!randomize_and_send_udp(pend, packet, timeout)) {
                pending_delete(sq->outnet, pend);
                return NULL;
        }
+       sq->busy = 0;
        return pend;
 }
 
@@ -2246,7 +2284,7 @@ reuse_tcp_select_id(struct reuse_tcp* reuse, struct outside_network* outnet)
        }
 
        /* equally pick a random unused element from the tree that is
-        * not in use.  Pick a the n-th index of an ununused number,
+        * not in use.  Pick a the n-th index of an unused number,
         * then loop over the empty spaces in the tree and find it */
        log_assert(reuse->tree_by_id.count < 0xffff);
        select = ub_random_max(outnet->rnd, 0xffff - reuse->tree_by_id.count);
@@ -2359,6 +2397,7 @@ pending_tcp_query(struct serviced_query* sq, sldns_buffer* packet,
 #ifdef USE_DNSTAP
        w->sq = NULL;
 #endif
+       w->in_cb_and_decommission = 0;
        if(pend) {
                /* we have a buffer available right now */
                if(reuse) {
@@ -2455,30 +2494,62 @@ lookup_serviced(struct outside_network* outnet, sldns_buffer* buff, int dnssec,
        return (struct serviced_query*)rbtree_search(outnet->serviced, &key);
 }
 
+void
+serviced_timer_cb(void* arg)
+{
+       struct serviced_query* sq = (struct serviced_query*)arg;
+       struct outside_network* outnet = sq->outnet;
+       verbose(VERB_ALGO, "serviced send timer");
+       /* By the time this cb is called, if we don't have any registered
+        * callbacks for this serviced_query anymore; do not send. */
+       if(!sq->cblist)
+               goto delete;
+       /* perform first network action */
+       if(outnet->do_udp && !(sq->tcp_upstream || sq->ssl_upstream)) {
+               if(!serviced_udp_send(sq, outnet->udp_buff))
+                       goto delete;
+       } else {
+               if(!serviced_tcp_send(sq, outnet->udp_buff))
+                       goto delete;
+       }
+       /* Maybe by this time we don't have callbacks attached anymore. Don't
+        * proactively try to delete; let it run and maybe another callback
+        * will get attached by the time we get an answer. */
+       return;
+delete:
+       serviced_callbacks(sq, NETEVENT_CLOSED, NULL, NULL);
+}
+
 /** Create new serviced entry */
 static struct serviced_query*
 serviced_create(struct outside_network* outnet, sldns_buffer* buff, int dnssec,
        int want_dnssec, int nocaps, int tcp_upstream, int ssl_upstream,
        char* tls_auth_name, struct sockaddr_storage* addr, socklen_t addrlen,
        uint8_t* zone, size_t zonelen, int qtype, struct edns_option* opt_list,
-       size_t pad_queries_block_size)
+       size_t pad_queries_block_size, struct alloc_cache* alloc,
+       struct regional* region)
 {
        struct serviced_query* sq = (struct serviced_query*)malloc(sizeof(*sq));
+       struct timeval t;
 #ifdef UNBOUND_DEBUG
        rbnode_type* ins;
 #endif
        if(!sq) 
                return NULL;
        sq->node.key = sq;
-       sq->qbuf = memdup(sldns_buffer_begin(buff), sldns_buffer_limit(buff));
+       sq->alloc = alloc;
+       sq->region = region;
+       sq->qbuf = regional_alloc_init(region, sldns_buffer_begin(buff),
+               sldns_buffer_limit(buff));
        if(!sq->qbuf) {
+               alloc_reg_release(alloc, region);
                free(sq);
                return NULL;
        }
        sq->qbuflen = sldns_buffer_limit(buff);
-       sq->zone = memdup(zone, zonelen);
+       sq->zone = regional_alloc_init(region, zone, zonelen);
        if(!sq->zone) {
-               free(sq->qbuf);
+               alloc_reg_release(alloc, region);
                free(sq);
                return NULL;
        }
@@ -2490,10 +2561,9 @@ serviced_create(struct outside_network* outnet, sldns_buffer* buff, int dnssec,
        sq->tcp_upstream = tcp_upstream;
        sq->ssl_upstream = ssl_upstream;
        if(tls_auth_name) {
-               sq->tls_auth_name = strdup(tls_auth_name);
+               sq->tls_auth_name = regional_strdup(region, tls_auth_name);
                if(!sq->tls_auth_name) {
-                       free(sq->zone);
-                       free(sq->qbuf);
+                       alloc_reg_release(alloc, region);
                        free(sq);
                        return NULL;
                }
@@ -2502,17 +2572,16 @@ serviced_create(struct outside_network* outnet, sldns_buffer* buff, int dnssec,
        }
        memcpy(&sq->addr, addr, addrlen);
        sq->addrlen = addrlen;
-       sq->opt_list = NULL;
-       if(opt_list) {
-               sq->opt_list = edns_opt_copy_alloc(opt_list);
-               if(!sq->opt_list) {
-                       free(sq->tls_auth_name);
-                       free(sq->zone);
-                       free(sq->qbuf);
-                       free(sq);
-                       return NULL;
-               }
+       sq->opt_list = opt_list;
+       sq->busy = 0;
+       sq->timer = comm_timer_create(outnet->base, serviced_timer_cb, sq);
+       if(!sq->timer) {
+               alloc_reg_release(alloc, region);
+               free(sq);
+               return NULL;
        }
+       memset(&t, 0, sizeof(t));
+       comm_timer_set(sq->timer, &t);
        sq->outnet = outnet;
        sq->cblist = NULL;
        sq->pending = NULL;
@@ -2521,7 +2590,7 @@ serviced_create(struct outside_network* outnet, sldns_buffer* buff, int dnssec,
        sq->to_be_deleted = 0;
        sq->padding_block_size = pad_queries_block_size;
 #ifdef UNBOUND_DEBUG
-       ins = 
+       ins =
 #else
        (void)
 #endif
@@ -2619,29 +2688,38 @@ serviced_delete(struct serviced_query* sq)
                        struct waiting_tcp* w = (struct waiting_tcp*)
                                sq->pending;
                        verbose(VERB_CLIENT, "serviced_delete: TCP");
+                       log_assert(!(w->write_wait_queued && w->on_tcp_waiting_list));
                        /* if on stream-write-waiting list then
                         * remove from waiting list and waiting_tcp_delete */
                        if(w->write_wait_queued) {
                                struct pending_tcp* pend =
                                        (struct pending_tcp*)w->next_waiting;
                                verbose(VERB_CLIENT, "serviced_delete: writewait");
-                               reuse_tree_by_id_delete(&pend->reuse, w);
+                               if(!w->in_cb_and_decommission)
+                                       reuse_tree_by_id_delete(&pend->reuse, w);
                                reuse_write_wait_remove(&pend->reuse, w);
-                               waiting_tcp_delete(w);
+                               if(!w->in_cb_and_decommission)
+                                       waiting_tcp_delete(w);
                        } else if(!w->on_tcp_waiting_list) {
                                struct pending_tcp* pend =
                                        (struct pending_tcp*)w->next_waiting;
                                verbose(VERB_CLIENT, "serviced_delete: tcpreusekeep");
+                               /* w needs to stay on tree_by_id to not assign
+                                * the same ID; remove the callback since its
+                                * serviced_query will be gone. */
+                               w->cb = NULL;
                                if(!reuse_tcp_remove_serviced_keep(w, sq)) {
-                                       reuse_cb_and_decommission(sq->outnet,
-                                               pend, NETEVENT_CLOSED);
+                                       if(!w->in_cb_and_decommission)
+                                               reuse_cb_and_decommission(sq->outnet,
+                                                       pend, NETEVENT_CLOSED);
                                        use_free_buffer(sq->outnet);
                                }
                                sq->pending = NULL;
                        } else {
                                verbose(VERB_CLIENT, "serviced_delete: tcpwait");
                                waiting_list_remove(sq->outnet, w);
-                               waiting_tcp_delete(w);
+                               if(!w->in_cb_and_decommission)
+                                       waiting_tcp_delete(w);
                        }
                }
        }
@@ -2708,7 +2786,9 @@ serviced_encode(struct serviced_query* sq, sldns_buffer* buff, int with_edns)
                edns.edns_present = 1;
                edns.ext_rcode = 0;
                edns.edns_version = EDNS_ADVERTISED_VERSION;
-               edns.opt_list = sq->opt_list;
+               edns.opt_list_in = NULL;
+               edns.opt_list_out = sq->opt_list;
+               edns.opt_list_inplace_cb_out = NULL;
                if(sq->status == serviced_query_UDP_EDNS_FRAG) {
                        if(addr_is_ip6(&sq->addr, sq->addrlen)) {
                                if(EDNS_FRAG_SIZE_IP6 < EDNS_ADVERTISED_SIZE)
@@ -2731,8 +2811,8 @@ serviced_encode(struct serviced_query* sq, sldns_buffer* buff, int with_edns)
                        padding_option.opt_code = LDNS_EDNS_PADDING;
                        padding_option.opt_len = 0;
                        padding_option.opt_data = NULL;
-                       padding_option.next = edns.opt_list;
-                       edns.opt_list = &padding_option;
+                       padding_option.next = edns.opt_list_out;
+                       edns.opt_list_out = &padding_option;
                        edns.padding_block_size = sq->padding_block_size;
                }
                attach_edns_record(buff, &edns);
@@ -2889,7 +2969,8 @@ serviced_callbacks(struct serviced_query* sq, int error, struct comm_point* c,
                 * use secondary buffer to store the query.
                 * This is a data copy, but faster than packet to server */
                backlen = sldns_buffer_limit(c->buffer);
-               backup_p = memdup(sldns_buffer_begin(c->buffer), backlen);
+               backup_p = regional_alloc_init(sq->region,
+                       sldns_buffer_begin(c->buffer), backlen);
                if(!backup_p) {
                        log_err("malloc failure in serviced query callbacks");
                        error = NETEVENT_CLOSED;
@@ -2907,10 +2988,8 @@ serviced_callbacks(struct serviced_query* sq, int error, struct comm_point* c,
                }
                fptr_ok(fptr_whitelist_serviced_query(p->cb));
                (void)(*p->cb)(c, p->cb_arg, error, rep);
-               free(p);
        }
        if(backup_p) {
-               free(backup_p);
                sq->outnet->svcd_overhead = 0;
        }
        verbose(VERB_ALGO, "svcd callbacks end");
@@ -2928,7 +3007,7 @@ serviced_tcp_callback(struct comm_point* c, void* arg, int error,
        struct waiting_tcp* w = (struct waiting_tcp*)sq->pending;
        struct pending_tcp* pend_tcp = NULL;
        struct port_if* pi = NULL;
-       if(!w->on_tcp_waiting_list && w->next_waiting) {
+       if(w && !w->on_tcp_waiting_list && w->next_waiting) {
                pend_tcp = (struct pending_tcp*)w->next_waiting;
                pi = pend_tcp->pi;
        }
@@ -3024,8 +3103,11 @@ serviced_tcp_initiate(struct serviced_query* sq, sldns_buffer* buff)
                sq->status==serviced_query_TCP_EDNS?"EDNS":"");
        serviced_encode(sq, buff, sq->status == serviced_query_TCP_EDNS);
        sq->last_sent_time = *sq->outnet->now_tv;
+       log_assert(!sq->busy);
+       sq->busy = 1;
        sq->pending = pending_tcp_query(sq, buff, sq->outnet->tcp_auth_query_timeout,
                serviced_tcp_callback, sq);
+       sq->busy = 0;
        if(!sq->pending) {
                /* delete from tree so that a retry by above layer does not
                 * clash with this entry */
@@ -3057,8 +3139,11 @@ serviced_tcp_send(struct serviced_query* sq, sldns_buffer* buff)
        } else {
                timeout = sq->outnet->tcp_auth_query_timeout;
        }
+       log_assert(!sq->busy);
+       sq->busy = 1;
        sq->pending = pending_tcp_query(sq, buff, timeout,
                serviced_tcp_callback, sq);
+       sq->busy = 0;
        return sq->pending != NULL;
 }
 
@@ -3109,7 +3194,6 @@ serviced_udp_callback(struct comm_point* c, void* arg, int error,
        struct timeval now = *sq->outnet->now_tv;
 #ifdef USE_DNSTAP
        struct pending* p = (struct pending*)sq->pending;
-       struct port_if* pi = p->pc->pif;
 #endif
 
        sq->pending = NULL; /* removed after callback */
@@ -3151,14 +3235,16 @@ serviced_udp_callback(struct comm_point* c, void* arg, int error,
        /*
         * sending src (local service)/dst (upstream) addresses over DNSTAP
         */
-       if(error == NETEVENT_NOERROR && outnet->dtenv &&
-          (outnet->dtenv->log_resolver_response_messages ||
-           outnet->dtenv->log_forwarder_response_messages)) {
+       if(error == NETEVENT_NOERROR && outnet->dtenv && p->pc &&
+               (outnet->dtenv->log_resolver_response_messages ||
+               outnet->dtenv->log_forwarder_response_messages)) {
                log_addr(VERB_ALGO, "response from upstream", &sq->addr, sq->addrlen);
-               log_addr(VERB_ALGO, "to local addr", &pi->addr, pi->addrlen);
-               dt_msg_send_outside_response(outnet->dtenv, &sq->addr, &pi->addr, c->type,
-                 sq->zone, sq->zonelen, sq->qbuf, sq->qbuflen,
-                 &sq->last_sent_time, sq->outnet->now_tv, c->buffer);
+               log_addr(VERB_ALGO, "to local addr", &p->pc->pif->addr,
+                       p->pc->pif->addrlen);
+               dt_msg_send_outside_response(outnet->dtenv, &sq->addr,
+                       &p->pc->pif->addr, c->type, sq->zone, sq->zonelen,
+                       sq->qbuf, sq->qbuflen, &sq->last_sent_time,
+                       sq->outnet->now_tv, c->buffer);
        }
 #endif
        if( (sq->status == serviced_query_UDP_EDNS 
@@ -3248,64 +3334,117 @@ serviced_udp_callback(struct comm_point* c, void* arg, int error,
 struct serviced_query* 
 outnet_serviced_query(struct outside_network* outnet,
        struct query_info* qinfo, uint16_t flags, int dnssec, int want_dnssec,
-       int nocaps, int tcp_upstream, int ssl_upstream, char* tls_auth_name,
-       struct sockaddr_storage* addr, socklen_t addrlen, uint8_t* zone,
-       size_t zonelen, struct module_qstate* qstate,
-       comm_point_callback_type* callback, void* callback_arg, sldns_buffer* buff,
-       struct module_env* env)
+       int nocaps, int check_ratelimit, int tcp_upstream, int ssl_upstream,
+       char* tls_auth_name, struct sockaddr_storage* addr, socklen_t addrlen,
+       uint8_t* zone, size_t zonelen, struct module_qstate* qstate,
+       comm_point_callback_type* callback, void* callback_arg,
+       sldns_buffer* buff, struct module_env* env, int* was_ratelimited)
 {
        struct serviced_query* sq;
        struct service_callback* cb;
        struct edns_string_addr* client_string_addr;
-
-       if(!inplace_cb_query_call(env, qinfo, flags, addr, addrlen, zone, zonelen,
-               qstate, qstate->region))
+       struct regional* region;
+       struct edns_option* backed_up_opt_list = qstate->edns_opts_back_out;
+       struct edns_option* per_upstream_opt_list = NULL;
+       time_t timenow = 0;
+
+       /* If we have an already populated EDNS option list make a copy since
+        * we may now add upstream specific EDNS options. */
+       /* Use a region that could be attached to a serviced_query, if it needs
+        * to be created. If an existing one is found then this region will be
+        * destroyed here. */
+       region = alloc_reg_obtain(env->alloc);
+       if(!region) return NULL;
+       if(qstate->edns_opts_back_out) {
+               per_upstream_opt_list = edns_opt_copy_region(
+                       qstate->edns_opts_back_out, region);
+               if(!per_upstream_opt_list) {
+                       alloc_reg_release(env->alloc, region);
                        return NULL;
+               }
+               qstate->edns_opts_back_out = per_upstream_opt_list;
+       }
+
+       if(!inplace_cb_query_call(env, qinfo, flags, addr, addrlen, zone,
+               zonelen, qstate, region)) {
+               alloc_reg_release(env->alloc, region);
+               return NULL;
+       }
+       /* Restore the option list; we can explicitly use the copied one from
+        * now on. */
+       per_upstream_opt_list = qstate->edns_opts_back_out;
+       qstate->edns_opts_back_out = backed_up_opt_list;
 
        if((client_string_addr = edns_string_addr_lookup(
                &env->edns_strings->client_strings, addr, addrlen))) {
-               edns_opt_list_append(&qstate->edns_opts_back_out,
+               edns_opt_list_append(&per_upstream_opt_list,
                        env->edns_strings->client_string_opcode,
                        client_string_addr->string_len,
-                       client_string_addr->string, qstate->region);
+                       client_string_addr->string, region);
        }
 
        serviced_gen_query(buff, qinfo->qname, qinfo->qname_len, qinfo->qtype,
                qinfo->qclass, flags);
        sq = lookup_serviced(outnet, buff, dnssec, addr, addrlen,
-               qstate->edns_opts_back_out);
-       /* duplicate entries are included in the callback list, because
-        * there is a counterpart registration by our caller that needs to
-        * be doubly-removed (with callbacks perhaps). */
-       if(!(cb = (struct service_callback*)malloc(sizeof(*cb))))
-               return NULL;
+               per_upstream_opt_list);
        if(!sq) {
+               /* Check ratelimit only for new serviced_query */
+               if(check_ratelimit) {
+                       timenow = *env->now;
+                       if(!infra_ratelimit_inc(env->infra_cache, zone,
+                               zonelen, timenow, env->cfg->ratelimit_backoff,
+                               &qstate->qinfo, qstate->reply)) {
+                               /* Can we pass through with slip factor? */
+                               if(env->cfg->ratelimit_factor == 0 ||
+                                       ub_random_max(env->rnd,
+                                       env->cfg->ratelimit_factor) != 1) {
+                                       *was_ratelimited = 1;
+                                       alloc_reg_release(env->alloc, region);
+                                       return NULL;
+                               }
+                               log_nametypeclass(VERB_ALGO,
+                                       "ratelimit allowed through for "
+                                       "delegation point", zone,
+                                       LDNS_RR_TYPE_NS, LDNS_RR_CLASS_IN);
+                       }
+               }
                /* make new serviced query entry */
                sq = serviced_create(outnet, buff, dnssec, want_dnssec, nocaps,
                        tcp_upstream, ssl_upstream, tls_auth_name, addr,
                        addrlen, zone, zonelen, (int)qinfo->qtype,
-                       qstate->edns_opts_back_out,
+                       per_upstream_opt_list,
                        ( ssl_upstream && env->cfg->pad_queries
-                       ? env->cfg->pad_queries_block_size : 0 ));
+                       ? env->cfg->pad_queries_block_size : 0 ),
+                       env->alloc, region);
                if(!sq) {
-                       free(cb);
+                       if(check_ratelimit) {
+                               infra_ratelimit_dec(env->infra_cache,
+                                       zone, zonelen, timenow);
+                       }
+                       alloc_reg_release(env->alloc, region);
                        return NULL;
                }
-               /* perform first network action */
-               if(outnet->do_udp && !(tcp_upstream || ssl_upstream)) {
-                       if(!serviced_udp_send(sq, buff)) {
-                               (void)rbtree_delete(outnet->serviced, sq);
-                               serviced_node_del(&sq->node, NULL);
-                               free(cb);
-                               return NULL;
-                       }
-               } else {
-                       if(!serviced_tcp_send(sq, buff)) {
-                               (void)rbtree_delete(outnet->serviced, sq);
-                               serviced_node_del(&sq->node, NULL);
-                               free(cb);
-                               return NULL;
+               if(!(cb = (struct service_callback*)regional_alloc(
+                       sq->region, sizeof(*cb)))) {
+                       if(check_ratelimit) {
+                               infra_ratelimit_dec(env->infra_cache,
+                                       zone, zonelen, timenow);
                        }
+                       (void)rbtree_delete(outnet->serviced, sq);
+                       serviced_node_del(&sq->node, NULL);
+                       return NULL;
+               }
+               /* No network action at this point; it will be invoked with the
+                * serviced_query timer instead to run outside of the mesh. */
+       } else {
+               /* We don't need this region anymore. */
+               alloc_reg_release(env->alloc, region);
+               /* duplicate entries are included in the callback list, because
+                * there is a counterpart registration by our caller that needs
+                * to be doubly-removed (with callbacks perhaps). */
+               if(!(cb = (struct service_callback*)regional_alloc(
+                       sq->region, sizeof(*cb)))) {
+                       return NULL;
                }
        }
        /* add callback to list of callbacks */
@@ -3325,7 +3464,6 @@ callback_list_remove(struct serviced_query* sq, void* cb_arg)
                if((*pp)->cb_arg == cb_arg) {
                        struct service_callback* del = *pp;
                        *pp = del->next;
-                       free(del);
                        return;
                }
                pp = &(*pp)->next;
@@ -3334,13 +3472,13 @@ callback_list_remove(struct serviced_query* sq, void* cb_arg)
 
 void outnet_serviced_query_stop(struct serviced_query* sq, void* cb_arg)
 {
-       if(!sq) 
+       if(!sq)
                return;
        callback_list_remove(sq, cb_arg);
        /* if callbacks() routine scheduled deletion, let it do that */
-       if(!sq->cblist && !sq->to_be_deleted) {
+       if(!sq->cblist && !sq->busy && !sq->to_be_deleted) {
                (void)rbtree_delete(sq->outnet->serviced, sq);
-               serviced_delete(sq); 
+               serviced_delete(sq);
        }
 }
 
index d0d532e..4c5b96f 100644 (file)
@@ -43,7 +43,9 @@
 #ifndef OUTSIDE_NETWORK_H
 #define OUTSIDE_NETWORK_H
 
+#include "util/alloc.h"
 #include "util/rbtree.h"
+#include "util/regional.h"
 #include "util/netevent.h"
 #include "dnstap/dnstap_config.h"
 struct pending;
@@ -412,6 +414,8 @@ struct waiting_tcp {
        char* tls_auth_name;
        /** the packet was involved in an error, to stop looping errors */
        int error_count;
+       /** if true, the item is at the cb_and_decommission stage */
+       int in_cb_and_decommission;
 #ifdef USE_DNSTAP
        /** serviced query pointer for dnstap to get logging info, if nonNULL*/
        struct serviced_query* sq;
@@ -512,6 +516,15 @@ struct serviced_query {
        void* pending;
        /** block size with which to pad encrypted queries (default: 128) */
        size_t padding_block_size;
+       /** region for this serviced query. Will be cleared when this
+        * serviced_query will be deleted */
+       struct regional* region;
+       /** allocation service for the region */
+       struct alloc_cache* alloc;
+       /** flash timer to start the net I/O as a separate event */
+       struct comm_timer* timer;
+       /** true if serviced_query is currently doing net I/O and may block */
+       int busy;
 };
 
 /**
@@ -619,6 +632,7 @@ void pending_delete(struct outside_network* outnet, struct pending* p);
  * @param want_dnssec: signatures are needed, without EDNS the answer is
  *     likely to be useless.
  * @param nocaps: ignore use_caps_for_id and use unperturbed qname.
+ * @param check_ratelimit: if set, will check ratelimit before sending out.
  * @param tcp_upstream: use TCP for upstream queries.
  * @param ssl_upstream: use SSL for upstream queries.
  * @param tls_auth_name: when ssl_upstream is true, use this name to check
@@ -635,16 +649,18 @@ void pending_delete(struct outside_network* outnet, struct pending* p);
  * @param callback_arg: user argument to callback function.
  * @param buff: scratch buffer to create query contents in. Empty on exit.
  * @param env: the module environment.
+ * @param was_ratelimited: it will signal back if the query failed to pass the
+ *     ratelimit check.
  * @return 0 on error, or pointer to serviced query that is used to answer
  *     this serviced query may be shared with other callbacks as well.
  */
 struct serviced_query* outnet_serviced_query(struct outside_network* outnet,
        struct query_info* qinfo, uint16_t flags, int dnssec, int want_dnssec,
-       int nocaps, int tcp_upstream, int ssl_upstream, char* tls_auth_name,
-       struct sockaddr_storage* addr, socklen_t addrlen, uint8_t* zone,
-       size_t zonelen, struct module_qstate* qstate,
+       int nocaps, int check_ratelimit, int tcp_upstream, int ssl_upstream,
+       char* tls_auth_name, struct sockaddr_storage* addr, socklen_t addrlen,
+       uint8_t* zone, size_t zonelen, struct module_qstate* qstate,
        comm_point_callback_type* callback, void* callback_arg,
-       struct sldns_buffer* buff, struct module_env* env);
+       struct sldns_buffer* buff, struct module_env* env, int* was_ratelimited);
 
 /**
  * Remove service query callback.
@@ -785,6 +801,9 @@ void pending_udp_timer_delay_cb(void *arg);
 /** callback for outgoing TCP timer event */
 void outnet_tcptimer(void* arg);
 
+/** callback to send serviced queries */
+void serviced_timer_cb(void *arg);
+
 /** callback for serviced query UDP answers */
 int serviced_udp_callback(struct comm_point* c, void* arg, int error,
         struct comm_reply* rep);
index a40f1e8..befe1f7 100644 (file)
@@ -250,7 +250,8 @@ sldns_key_buf2dsa_raw(unsigned char* key, size_t len)
        if(!(dsa = DSA_new())) {
                return NULL;
        }
-#if OPENSSL_VERSION_NUMBER < 0x10100000
+#if OPENSSL_VERSION_NUMBER < 0x10100000 || \
+        (defined(HAVE_LIBRESSL) && LIBRESSL_VERSION_NUMBER < 0x02070000f)
 #ifndef S_SPLINT_S
        dsa->p = P;
        dsa->q = Q;
@@ -428,7 +429,8 @@ sldns_key_buf2rsa_raw(unsigned char* key, size_t len)
                BN_free(modulus);
                return NULL;
        }
-#if OPENSSL_VERSION_NUMBER < 0x10100000
+#if OPENSSL_VERSION_NUMBER < 0x10100000 || \
+        (defined(HAVE_LIBRESSL) && LIBRESSL_VERSION_NUMBER < 0x02070000f)
 #ifndef S_SPLINT_S
        rsa->n = modulus;
        rsa->e = exponent;
index 74d7c72..208fd2f 100644 (file)
@@ -58,7 +58,7 @@ time_t sldns_mktime_from_utc(const struct tm *tm);
  * The function interprets time as the number of seconds since epoch
  * with respect to now using serial arithmetics (rfc1982).
  * That number of seconds is then converted to broken-out time information.
- * This is especially usefull when converting the inception and expiration
+ * This is especially useful when converting the inception and expiration
  * fields of RRSIG records.
  *
  * \param[in] time number of seconds since epoch (midnight, January 1st, 1970)
index fbd615c..d2cefae 100644 (file)
 #include <netdb.h>
 #endif
 
+/** bits for the offset */
+#define RET_OFFSET_MASK (((unsigned)(~LDNS_WIREPARSE_MASK))>>LDNS_WIREPARSE_SHIFT)
 /** return an error */
-#define RET_ERR(e, off) ((int)((e)|((off)<<LDNS_WIREPARSE_SHIFT)))
+#define RET_ERR(e, off) ((int)(((e)&LDNS_WIREPARSE_MASK)|(((off)&RET_OFFSET_MASK)<<LDNS_WIREPARSE_SHIFT)))
 /** Move parse error but keep its ID */
 #define RET_ERR_SHIFT(e, move) RET_ERR(LDNS_WIREPARSE_ERROR(e), LDNS_WIREPARSE_OFFSET(e)+(move));
 
@@ -543,9 +545,10 @@ sldns_parse_rdf_token(sldns_buffer* strbuf, char* token, size_t token_len,
 {
        size_t slen;
 
-       /* skip spaces */
+       /* skip spaces and tabs */
        while(sldns_buffer_remaining(strbuf) > 0 && !*quoted &&
-               *(sldns_buffer_current(strbuf)) == ' ') {
+               (*(sldns_buffer_current(strbuf)) == ' ' ||
+               *(sldns_buffer_current(strbuf)) == '\t')) {
                sldns_buffer_skip(strbuf, 1);
        }
 
@@ -601,7 +604,10 @@ sldns_affix_token(sldns_buffer* strbuf, char* token, size_t* token_len,
        size_t addstrlen = 0;
 
        /* add space */
-       if(addlen < 1) return 0;
+       /* when addlen < 2, the token buffer is full considering the NULL byte
+        * from strlen and will lead to buffer overflow with the second
+        * assignement below. */
+       if(addlen < 2) return 0;
        token[*token_strlen] = ' ';
        token[++(*token_strlen)] = 0;
 
@@ -1427,7 +1433,7 @@ sldns_str2wire_svcbparam_parse_next_unescaped_comma(const char *val)
 }
 
 /* The source is already properly unescaped, this double unescaping is purely to allow for
- * comma's in comma seperated alpn lists.
+ * comma's in comma separated alpn lists.
  * 
  * In draft-ietf-dnsop-svcb-https-06 Section 7:
  * To enable simpler parsing, this SvcParamValue MUST NOT contain escape sequences.
@@ -1565,7 +1571,7 @@ sldns_str2wire_svcparam_value(const char *key, size_t key_len,
        return LDNS_WIREPARSE_ERR_GENERAL;
 }
 
-int sldns_str2wire_svcparam_buf(const char* str, uint8_t* rd, size_t* rd_len)
+static int sldns_str2wire_svcparam_buf(const char* str, uint8_t* rd, size_t* rd_len)
 {
        const char* eq_pos;
        char unescaped_val[LDNS_MAX_RDFLEN];
index 0c31649..baee423 100644 (file)
@@ -187,7 +187,7 @@ uint8_t* sldns_wirerr_get_rdatawl(uint8_t* rr, size_t len, size_t dname_len);
 #define LDNS_WIREPARSE_MASK 0x0fff
 #define LDNS_WIREPARSE_SHIFT 12
 #define LDNS_WIREPARSE_ERROR(e) ((e)&LDNS_WIREPARSE_MASK)
-#define LDNS_WIREPARSE_OFFSET(e) (((e)&~LDNS_WIREPARSE_MASK)>>LDNS_WIREPARSE_SHIFT)
+#define LDNS_WIREPARSE_OFFSET(e) ((((unsigned)(e))&~LDNS_WIREPARSE_MASK)>>LDNS_WIREPARSE_SHIFT)
 /* use lookuptable to get error string, sldns_wireparse_errors */
 #define LDNS_WIREPARSE_ERR_OK 0
 #define LDNS_WIREPARSE_ERR_GENERAL 342
index 6a177ec..b70efe2 100644 (file)
@@ -817,6 +817,7 @@ int sldns_wire2str_dname_scan(uint8_t** d, size_t* dlen, char** s, size_t* slen,
        unsigned i, counter=0;
        unsigned maxcompr = MAX_COMPRESS_PTRS; /* loop detection, max compr ptrs */
        int in_buf = 1;
+       size_t dname_len = 0;
        if(comprloop) {
                if(*comprloop != 0)
                        maxcompr = 30; /* for like ipv6 reverse name, per label */
@@ -872,6 +873,16 @@ int sldns_wire2str_dname_scan(uint8_t** d, size_t* dlen, char** s, size_t* slen,
                        labellen = (uint8_t)*dlen;
                else if(!in_buf && pos+(size_t)labellen > pkt+pktlen)
                        labellen = (uint8_t)(pkt + pktlen - pos);
+               dname_len += ((size_t)labellen)+1;
+               if(dname_len > LDNS_MAX_DOMAINLEN) {
+                       /* dname_len counts the uncompressed length we have
+                        * seen so far, and the domain name has become too
+                        * long, prevent the loop from printing overly long
+                        * content. */
+                       w += sldns_str_print(s, slen,
+                               "ErrorDomainNameTooLong");
+                       return w;
+               }
                for(i=0; i<(unsigned)labellen; i++) {
                        w += dname_char_print(s, slen, *pos++);
                }
index b1ad459..548c663 100644 (file)
@@ -59,7 +59,7 @@ char* sldns_wire2str_pkt(uint8_t* data, size_t len);
 char* sldns_wire2str_rr(uint8_t* rr, size_t len);
 
 /**
- * Conver wire dname to a string.
+ * Convert wire dname to a string.
  * @param dname: the dname in uncompressed wireformat.
  * @param dname_len: length of the dname.
  * @return string or NULL on failure.
index dbd5f12..8b371e9 100644 (file)
@@ -2048,13 +2048,13 @@ write_builtin_anchor(const char* file)
        const char* builtin_root_anchor = get_builtin_ds();
        FILE* out = fopen(file, "w");
        if(!out) {
-               if(verb) printf("%s: %s\n", file, strerror(errno));
-               if(verb) printf("  could not write builtin anchor\n");
+               printf("could not write builtin anchor, to file %s: %s\n",
+                       file, strerror(errno));
                return;
        }
        if(!fwrite(builtin_root_anchor, strlen(builtin_root_anchor), 1, out)) {
-               if(verb) printf("%s: %s\n", file, strerror(errno));
-               if(verb) printf("  could not complete write builtin anchor\n");
+               printf("could not complete write builtin anchor, to file %s: %s\n",
+                       file, strerror(errno));
        }
        fclose(out);
 }
index 68f1a4c..55c3be3 100644 (file)
@@ -54,6 +54,7 @@
 #include "iterator/iter_hints.h"
 #include "validator/validator.h"
 #include "services/localzone.h"
+#include "services/listen_dnsport.h"
 #include "services/view.h"
 #include "services/authzone.h"
 #include "respip/respip.h"
@@ -334,19 +335,64 @@ interfacechecks(struct config_file* cfg)
        int d;
        struct sockaddr_storage a;
        socklen_t alen;
-       int i, j;
+       int i, j, i2, j2;
+       char*** resif = NULL;
+       int* num_resif = NULL;
+
+       if(cfg->num_ifs != 0) {
+               resif = (char***)calloc(cfg->num_ifs, sizeof(char**));
+               if(!resif) fatal_exit("malloc failure");
+               num_resif = (int*)calloc(cfg->num_ifs, sizeof(int));
+               if(!num_resif) fatal_exit("malloc failure");
+       }
        for(i=0; i<cfg->num_ifs; i++) {
-               if(!extstrtoaddr(cfg->ifs[i], &a, &alen)) {
-                       fatal_exit("cannot parse interface specified as '%s'",
-                               cfg->ifs[i]);
-               }
-               for(j=0; j<cfg->num_ifs; j++) {
-                       if(i!=j && strcmp(cfg->ifs[i], cfg->ifs[j])==0)
+               /* search for duplicates in IP or ifname arguments */
+               for(i2=0; i2<i; i2++) {
+                       if(strcmp(cfg->ifs[i], cfg->ifs[i2]) == 0) {
                                fatal_exit("interface: %s present twice, "
                                        "cannot bind same ports twice.",
                                        cfg->ifs[i]);
+                       }
+               }
+               if(!resolve_interface_names(&cfg->ifs[i], 1, NULL, &resif[i],
+                       &num_resif[i])) {
+                       fatal_exit("could not resolve interface names, for %s",
+                               cfg->ifs[i]);
+               }
+               /* search for duplicates in the returned addresses */
+               for(j=0; j<num_resif[i]; j++) {
+                       if(!extstrtoaddr(resif[i][j], &a, &alen)) {
+                               if(strcmp(cfg->ifs[i], resif[i][j]) != 0)
+                                       fatal_exit("cannot parse interface address '%s' from the interface specified as '%s'",
+                                               resif[i][j], cfg->ifs[i]);
+                               else
+                                       fatal_exit("cannot parse interface specified as '%s'",
+                                               cfg->ifs[i]);
+                       }
+                       for(i2=0; i2<i; i2++) {
+                               for(j2=0; j2<num_resif[i2]; j2++) {
+                                       if(strcmp(resif[i][j], resif[i2][j2])
+                                               == 0) {
+                                               char info1[1024], info2[1024];
+                                               if(strcmp(cfg->ifs[i], resif[i][j]) != 0)
+                                                       snprintf(info1, sizeof(info1), "address %s from interface: %s", resif[i][j], cfg->ifs[i]);
+                                               else    snprintf(info1, sizeof(info1), "interface: %s", cfg->ifs[i]);
+                                               if(strcmp(cfg->ifs[i2], resif[i2][j2]) != 0)
+                                                       snprintf(info2, sizeof(info2), "address %s from interface: %s", resif[i2][j2], cfg->ifs[i2]);
+                                               else    snprintf(info2, sizeof(info2), "interface: %s", cfg->ifs[i2]);
+                                               fatal_exit("%s present twice, cannot bind the same ports twice. The first entry is %s and the second is %s", resif[i][j], info2, info1);
+                                       }
+                               }
+                       }
                }
        }
+
+       for(i=0; i<cfg->num_ifs; i++) {
+               config_del_strarray(resif[i], num_resif[i]);
+       }
+       free(resif);
+       free(num_resif);
+
        for(i=0; i<cfg->num_out_ifs; i++) {
                if(!ipstrtoaddr(cfg->out_ifs[i], UNBOUND_DNS_PORT, &a, &alen) &&
                   !netblockstrtoaddr(cfg->out_ifs[i], UNBOUND_DNS_PORT, &a, &alen, &d)) {
@@ -645,6 +691,8 @@ morechecks(struct config_file* cfg)
                && strcmp(cfg->module_conf, "dns64 iterator") != 0
                && strcmp(cfg->module_conf, "respip iterator") != 0
                && strcmp(cfg->module_conf, "respip validator iterator") != 0
+               && strcmp(cfg->module_conf, "respip dns64 validator iterator") != 0
+               && strcmp(cfg->module_conf, "respip dns64 iterator") != 0
 #ifdef WITH_PYTHONMODULE
                && strcmp(cfg->module_conf, "python iterator") != 0
                && strcmp(cfg->module_conf, "python respip iterator") != 0
@@ -739,6 +787,10 @@ morechecks(struct config_file* cfg)
                && strcmp(cfg->module_conf, "validator python cachedb iterator") != 0
                && strcmp(cfg->module_conf, "respip validator python cachedb iterator") != 0
 #endif
+#if defined(CLIENT_SUBNET) && defined(USE_CACHEDB)
+               && strcmp(cfg->module_conf, "respip subnetcache validator cachedb iterator") != 0
+               && strcmp(cfg->module_conf, "subnetcache validator cachedb iterator") != 0
+#endif
 #ifdef CLIENT_SUBNET
                && strcmp(cfg->module_conf, "subnetcache iterator") != 0
                && strcmp(cfg->module_conf, "respip subnetcache iterator") != 0
@@ -913,9 +965,9 @@ int main(int argc, char* argv[])
        const char* f;
        const char* opt = NULL;
        const char* cfgfile = CONFIGFILE;
+       checklock_start();
        log_ident_set("unbound-checkconf");
        log_init(NULL, 0, NULL);
-       checklock_start();
 #ifdef USE_WINSOCK
        /* use registry config file in preference to compiletime location */
        if(!(cfgfile=w_lookup_reg_str("Software\\Unbound", "ConfigFile")))
@@ -944,7 +996,7 @@ int main(int argc, char* argv[])
                f = argv[0];
        else    f = cfgfile;
 
-       if (pledge("stdio rpath getpw", NULL) == -1)
+       if (pledge("stdio rpath dns getpw", NULL) == -1)
                fatal_exit("Could not pledge");
 
        checkconf(f, opt, final);
index a3df257..c7c3827 100644 (file)
@@ -944,9 +944,9 @@ int main(int argc, char* argv[])
        extern int check_locking_order;
        check_locking_order = 0;
 #endif /* USE_THREAD_DEBUG */
+       checklock_start();
        log_ident_set("unbound-control");
        log_init(NULL, 0, NULL);
-       checklock_start();
 #ifdef USE_WINSOCK
        /* use registry config file in preference to compiletime location */
        if(!(cfgfile=w_lookup_reg_str("Software\\Unbound", "ConfigFile")))
index 473e32a..c689817 100644 (file)
@@ -97,10 +97,12 @@ void worker_sighandler(int ATTR_UNUSED(sig), void* ATTR_UNUSED(arg))
 struct outbound_entry* worker_send_query(
        struct query_info* ATTR_UNUSED(qinfo), uint16_t ATTR_UNUSED(flags),
        int ATTR_UNUSED(dnssec), int ATTR_UNUSED(want_dnssec),
-       int ATTR_UNUSED(nocaps), struct sockaddr_storage* ATTR_UNUSED(addr),
+       int ATTR_UNUSED(nocaps), int ATTR_UNUSED(check_ratelimit),
+       struct sockaddr_storage* ATTR_UNUSED(addr),
        socklen_t ATTR_UNUSED(addrlen), uint8_t* ATTR_UNUSED(zone),
-       size_t ATTR_UNUSED(zonelen), int ATTR_UNUSED(ssl_upstream),
-       char* ATTR_UNUSED(tls_auth_name), struct module_qstate* ATTR_UNUSED(q))
+       size_t ATTR_UNUSED(zonelen), int ATTR_UNUSED(tcp_upstream), int ATTR_UNUSED(ssl_upstream),
+       char* ATTR_UNUSED(tls_auth_name), struct module_qstate* ATTR_UNUSED(q),
+       int* ATTR_UNUSED(was_ratelimited))
 {
        log_assert(0);
        return 0;
@@ -129,10 +131,12 @@ worker_alloc_cleanup(void* ATTR_UNUSED(arg))
 struct outbound_entry* libworker_send_query(
        struct query_info* ATTR_UNUSED(qinfo), uint16_t ATTR_UNUSED(flags),
        int ATTR_UNUSED(dnssec), int ATTR_UNUSED(want_dnssec),
-       int ATTR_UNUSED(nocaps), struct sockaddr_storage* ATTR_UNUSED(addr),
+       int ATTR_UNUSED(nocaps), int ATTR_UNUSED(check_ratelimit),
+       struct sockaddr_storage* ATTR_UNUSED(addr),
        socklen_t ATTR_UNUSED(addrlen), uint8_t* ATTR_UNUSED(zone),
-       size_t ATTR_UNUSED(zonelen), int ATTR_UNUSED(ssl_upstream),
-       char* ATTR_UNUSED(tls_auth_name), struct module_qstate* ATTR_UNUSED(q))
+       size_t ATTR_UNUSED(zonelen), int ATTR_UNUSED(tcp_upstream), int ATTR_UNUSED(ssl_upstream),
+       char* ATTR_UNUSED(tls_auth_name), struct module_qstate* ATTR_UNUSED(q),
+       int* ATTR_UNUSED(was_ratelimited))
 {
        log_assert(0);
        return 0;
index 4725e7d..15a090c 100644 (file)
@@ -260,7 +260,7 @@ config_create(void)
        cfg->val_log_level = 0;
        cfg->val_log_squelch = 0;
        cfg->val_permissive_mode = 0;
-       cfg->aggressive_nsec = 0;
+       cfg->aggressive_nsec = 1;
        cfg->ignore_cd = 0;
        cfg->serve_expired = 0;
        cfg->serve_expired_ttl = 0;
@@ -330,6 +330,9 @@ config_create(void)
        cfg->ratelimit_below_domain = NULL;
        cfg->ip_ratelimit_factor = 10;
        cfg->ratelimit_factor = 10;
+       cfg->ip_ratelimit_backoff = 0;
+       cfg->ratelimit_backoff = 0;
+       cfg->outbound_msg_retry = 5;
        cfg->qname_minimisation = 1;
        cfg->qname_minimisation_strict = 0;
        cfg->shm_enable = 0;
@@ -530,11 +533,17 @@ int config_set_option(struct config_file* cfg, const char* opt,
        else S_YNO("edns-tcp-keepalive:", do_tcp_keepalive)
        else S_NUMBER_NONZERO("edns-tcp-keepalive-timeout:", tcp_keepalive_timeout)
        else S_YNO("ssl-upstream:", ssl_upstream)
+       else S_YNO("tls-upstream:", ssl_upstream)
        else S_STR("ssl-service-key:", ssl_service_key)
+       else S_STR("tls-service-key:", ssl_service_key)
        else S_STR("ssl-service-pem:", ssl_service_pem)
+       else S_STR("tls-service-pem:", ssl_service_pem)
        else S_NUMBER_NONZERO("ssl-port:", ssl_port)
+       else S_NUMBER_NONZERO("tls-port:", ssl_port)
+       else S_STR("ssl-cert-bundle:", tls_cert_bundle)
        else S_STR("tls-cert-bundle:", tls_cert_bundle)
        else S_YNO("tls-win-cert:", tls_win_cert)
+       else S_STRLIST("additional-ssl-port:", tls_additional_port)
        else S_STRLIST("additional-tls-port:", tls_additional_port)
        else S_STRLIST("tls-additional-ports:", tls_additional_port)
        else S_STRLIST("tls-additional-port:", tls_additional_port)
@@ -752,6 +761,9 @@ int config_set_option(struct config_file* cfg, const char* opt,
        else S_POW2("ratelimit-slabs:", ratelimit_slabs)
        else S_NUMBER_OR_ZERO("ip-ratelimit-factor:", ip_ratelimit_factor)
        else S_NUMBER_OR_ZERO("ratelimit-factor:", ratelimit_factor)
+       else S_YNO("ip-ratelimit-backoff:", ip_ratelimit_backoff)
+       else S_YNO("ratelimit-backoff:", ratelimit_backoff)
+       else S_NUMBER_NONZERO("outbound-msg-retry:", outbound_msg_retry)
        else S_SIZET_NONZERO("fast-server-num:", fast_server_num)
        else S_NUMBER_OR_ZERO("fast-server-permil:", fast_server_permil)
        else S_YNO("qname-minimisation:", qname_minimisation)
@@ -1027,11 +1039,19 @@ config_get_option(struct config_file* cfg, const char* opt,
        else O_YNO(opt, "edns-tcp-keepalive", do_tcp_keepalive)
        else O_DEC(opt, "edns-tcp-keepalive-timeout", tcp_keepalive_timeout)
        else O_YNO(opt, "ssl-upstream", ssl_upstream)
+       else O_YNO(opt, "tls-upstream", ssl_upstream)
        else O_STR(opt, "ssl-service-key", ssl_service_key)
+       else O_STR(opt, "tls-service-key", ssl_service_key)
        else O_STR(opt, "ssl-service-pem", ssl_service_pem)
+       else O_STR(opt, "tls-service-pem", ssl_service_pem)
        else O_DEC(opt, "ssl-port", ssl_port)
+       else O_DEC(opt, "tls-port", ssl_port)
+       else O_STR(opt, "ssl-cert-bundle", tls_cert_bundle)
        else O_STR(opt, "tls-cert-bundle", tls_cert_bundle)
        else O_YNO(opt, "tls-win-cert", tls_win_cert)
+       else O_LST(opt, "additional-ssl-port", tls_additional_port)
+       else O_LST(opt, "additional-tls-port", tls_additional_port)
+       else O_LST(opt, "tls-additional-ports", tls_additional_port)
        else O_LST(opt, "tls-additional-port", tls_additional_port)
        else O_LST(opt, "tls-session-ticket-keys", tls_session_ticket_keys.first)
        else O_STR(opt, "tls-ciphers", tls_ciphers)
@@ -1195,6 +1215,9 @@ config_get_option(struct config_file* cfg, const char* opt,
        else O_LS2(opt, "ratelimit-below-domain", ratelimit_below_domain)
        else O_DEC(opt, "ip-ratelimit-factor", ip_ratelimit_factor)
        else O_DEC(opt, "ratelimit-factor", ratelimit_factor)
+       else O_YNO(opt, "ip-ratelimit-backoff", ip_ratelimit_backoff)
+       else O_YNO(opt, "ratelimit-backoff", ratelimit_backoff)
+       else O_UNS(opt, "outbound-msg-retry", outbound_msg_retry)
        else O_DEC(opt, "fast-server-num", fast_server_num)
        else O_DEC(opt, "fast-server-permil", fast_server_permil)
        else O_DEC(opt, "val-sig-skew-min", val_sig_skew_min)
index aed6812..c7c9a0a 100644 (file)
@@ -565,6 +565,10 @@ struct config_file {
        size_t ip_ratelimit_size;
        /** ip_ratelimit factor, 0 blocks all, 10 allows 1/10 of traffic */
        int ip_ratelimit_factor;
+       /** ratelimit backoff, when on, if the limit is reached it is
+        *  considered an attack and it backs off until 'demand' decreases over
+        *  the RATE_WINDOW. */
+       int ip_ratelimit_backoff;
 
        /** ratelimit for domains. 0 is off, otherwise qps (unless overridden) */
        int ratelimit;
@@ -578,6 +582,13 @@ struct config_file {
        struct config_str2list* ratelimit_below_domain;
        /** ratelimit factor, 0 blocks all, 10 allows 1/10 of traffic */
        int ratelimit_factor;
+       /** ratelimit backoff, when on, if the limit is reached it is
+        *  considered an attack and it backs off until 'demand' decreases over
+        *  the RATE_WINDOW. */
+       int ratelimit_backoff;
+
+       /** number of retries on outgoing queries */
+       int outbound_msg_retry;
        /** minimise outgoing QNAME and hide original QTYPE if possible */
        int qname_minimisation;
        /** minimise QNAME in strict mode, minimise according to RFC.
@@ -697,6 +708,8 @@ struct config_stub {
        int isprime;
        /** if forward-first is set (failover to without if fails) */
        int isfirst;
+       /** use tcp for queries to this stub */
+       int tcp_upstream;
        /** use SSL for queries to this stub */
        int ssl_upstream;
        /*** no cache */
@@ -741,6 +754,8 @@ struct config_auth {
        /** Always reply with this CNAME target if the cname override action is
         * used */
        char* rpz_cname;
+       /** signal nxdomain block with unset RA */
+       int rpz_signal_nxdomain_ra;
        /** Check ZONEMD records for this zone */
        int zonemd_check;
        /** Reject absence of ZONEMD records, zone must have one */
@@ -1106,7 +1121,7 @@ int cfg_count_numbers(const char* str);
 int cfg_parse_memsize(const char* str, size_t* res);
 
 /**
- * Parse nsid from string into binary nsid. nsid is either a hexidecimal
+ * Parse nsid from string into binary nsid. nsid is either a hexadecimal
  * string or an ascii string prepended with ascii_ in which case the
  * characters after ascii_ are simply copied.
  * @param str: the string to parse.
index dbfc17d..34a0e5d 100644 (file)
@@ -331,6 +331,7 @@ stub-first{COLON}           { YDVAR(1, VAR_STUB_FIRST) }
 stub-no-cache{COLON}           { YDVAR(1, VAR_STUB_NO_CACHE) }
 stub-ssl-upstream{COLON}       { YDVAR(1, VAR_STUB_SSL_UPSTREAM) }
 stub-tls-upstream{COLON}       { YDVAR(1, VAR_STUB_SSL_UPSTREAM) }
+stub-tcp-upstream{COLON}       { YDVAR(1, VAR_STUB_TCP_UPSTREAM) }
 forward-zone{COLON}            { YDVAR(0, VAR_FORWARD_ZONE) }
 forward-addr{COLON}            { YDVAR(1, VAR_FORWARD_ADDR) }
 forward-host{COLON}            { YDVAR(1, VAR_FORWARD_HOST) }
@@ -338,6 +339,7 @@ forward-first{COLON}                { YDVAR(1, VAR_FORWARD_FIRST) }
 forward-no-cache{COLON}                { YDVAR(1, VAR_FORWARD_NO_CACHE) }
 forward-ssl-upstream{COLON}    { YDVAR(1, VAR_FORWARD_SSL_UPSTREAM) }
 forward-tls-upstream{COLON}    { YDVAR(1, VAR_FORWARD_SSL_UPSTREAM) }
+forward-tcp-upstream{COLON}    { YDVAR(1, VAR_FORWARD_TCP_UPSTREAM) }
 auth-zone{COLON}               { YDVAR(0, VAR_AUTH_ZONE) }
 rpz{COLON}                     { YDVAR(0, VAR_RPZ) }
 tags{COLON}                    { YDVAR(1, VAR_TAGS) }
@@ -345,6 +347,7 @@ rpz-action-override{COLON}  { YDVAR(1, VAR_RPZ_ACTION_OVERRIDE) }
 rpz-cname-override{COLON}      { YDVAR(1, VAR_RPZ_CNAME_OVERRIDE) }
 rpz-log{COLON}                 { YDVAR(1, VAR_RPZ_LOG) }
 rpz-log-name{COLON}            { YDVAR(1, VAR_RPZ_LOG_NAME) }
+rpz-signal-nxdomain-ra{COLON}  { YDVAR(1, VAR_RPZ_SIGNAL_NXDOMAIN_RA) }
 zonefile{COLON}                        { YDVAR(1, VAR_ZONEFILE) }
 master{COLON}                  { YDVAR(1, VAR_MASTER) }
 primary{COLON}                 { YDVAR(1, VAR_MASTER) }
@@ -499,6 +502,9 @@ ratelimit-for-domain{COLON} { YDVAR(2, VAR_RATELIMIT_FOR_DOMAIN) }
 ratelimit-below-domain{COLON}  { YDVAR(2, VAR_RATELIMIT_BELOW_DOMAIN) }
 ip-ratelimit-factor{COLON}             { YDVAR(1, VAR_IP_RATELIMIT_FACTOR) }
 ratelimit-factor{COLON}                { YDVAR(1, VAR_RATELIMIT_FACTOR) }
+ip-ratelimit-backoff{COLON}            { YDVAR(1, VAR_IP_RATELIMIT_BACKOFF) }
+ratelimit-backoff{COLON}               { YDVAR(1, VAR_RATELIMIT_BACKOFF) }
+outbound-msg-retry{COLON}              { YDVAR(1, VAR_OUTBOUND_MSG_RETRY) }
 low-rtt{COLON}                 { YDVAR(1, VAR_LOW_RTT) }
 fast-server-num{COLON}         { YDVAR(1, VAR_FAST_SERVER_NUM) }
 low-rtt-pct{COLON}             { YDVAR(1, VAR_FAST_SERVER_PERMIL) }
index e22d48d..d4f965f 100644 (file)
@@ -4,24 +4,24 @@
  * Copyright (c) 2001-2006, NLnet Labs. All rights reserved.
  *
  * Copyright (c) 2007, NLnet Labs. All rights reserved.
- * 
+ *
  * This software is open source.
- * 
+ *
  * Redistribution and use in source and binary forms, with or without
  * modification, are permitted provided that the following conditions
  * are met:
- * 
+ *
  * Redistributions of source code must retain the above copyright notice,
  * this list of conditions and the following disclaimer.
- * 
+ *
  * Redistributions in binary form must reproduce the above copyright notice,
  * this list of conditions and the following disclaimer in the documentation
  * and/or other materials provided with the distribution.
- * 
+ *
  * Neither the name of the NLNET LABS nor the names of its contributors may
  * be used to endorse or promote products derived from this software without
  * specific prior written permission.
- * 
+ *
  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
  * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
  * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
@@ -88,13 +88,13 @@ extern struct config_parser_state* cfg_parser;
 %token VAR_TRUST_ANCHOR_FILE VAR_TRUST_ANCHOR VAR_VAL_OVERRIDE_DATE
 %token VAR_BOGUS_TTL VAR_VAL_CLEAN_ADDITIONAL VAR_VAL_PERMISSIVE_MODE
 %token VAR_INCOMING_NUM_TCP VAR_MSG_BUFFER_SIZE VAR_KEY_CACHE_SIZE
-%token VAR_KEY_CACHE_SLABS VAR_TRUSTED_KEYS_FILE 
-%token VAR_VAL_NSEC3_KEYSIZE_ITERATIONS VAR_USE_SYSLOG 
+%token VAR_KEY_CACHE_SLABS VAR_TRUSTED_KEYS_FILE
+%token VAR_VAL_NSEC3_KEYSIZE_ITERATIONS VAR_USE_SYSLOG
 %token VAR_OUTGOING_INTERFACE VAR_ROOT_HINTS VAR_DO_NOT_QUERY_LOCALHOST
 %token VAR_CACHE_MAX_TTL VAR_HARDEN_DNSSEC_STRIPPED VAR_ACCESS_CONTROL
 %token VAR_LOCAL_ZONE VAR_LOCAL_DATA VAR_INTERFACE_AUTOMATIC
 %token VAR_STATISTICS_INTERVAL VAR_DO_DAEMONIZE VAR_USE_CAPS_FOR_ID
-%token VAR_STATISTICS_CUMULATIVE VAR_OUTGOING_PORT_PERMIT 
+%token VAR_STATISTICS_CUMULATIVE VAR_OUTGOING_PORT_PERMIT
 %token VAR_OUTGOING_PORT_AVOID VAR_DLV_ANCHOR_FILE VAR_DLV_ANCHOR
 %token VAR_NEG_CACHE_SIZE VAR_HARDEN_REFERRAL_PATH VAR_PRIVATE_ADDRESS
 %token VAR_PRIVATE_DOMAIN VAR_REMOTE_CONTROL VAR_CONTROL_ENABLE
@@ -113,6 +113,7 @@ extern struct config_parser_state* cfg_parser;
 %token VAR_SSL_UPSTREAM VAR_TCP_AUTH_QUERY_TIMEOUT VAR_SSL_SERVICE_KEY
 %token VAR_SSL_SERVICE_PEM VAR_SSL_PORT VAR_FORWARD_FIRST
 %token VAR_STUB_SSL_UPSTREAM VAR_FORWARD_SSL_UPSTREAM VAR_TLS_CERT_BUNDLE
+%token VAR_STUB_TCP_UPSTREAM VAR_FORWARD_TCP_UPSTREAM
 %token VAR_HTTPS_PORT VAR_HTTP_ENDPOINT VAR_HTTP_MAX_STREAMS
 %token VAR_HTTP_QUERY_BUFFER_SIZE VAR_HTTP_RESPONSE_BUFFER_SIZE
 %token VAR_HTTP_NODELAY VAR_HTTP_NOTLS_DOWNSTREAM
@@ -138,8 +139,10 @@ extern struct config_parser_state* cfg_parser;
 %token VAR_DISABLE_DNSSEC_LAME_CHECK
 %token VAR_IP_RATELIMIT VAR_IP_RATELIMIT_SLABS VAR_IP_RATELIMIT_SIZE
 %token VAR_RATELIMIT VAR_RATELIMIT_SLABS VAR_RATELIMIT_SIZE
+%token VAR_OUTBOUND_MSG_RETRY
 %token VAR_RATELIMIT_FOR_DOMAIN VAR_RATELIMIT_BELOW_DOMAIN
 %token VAR_IP_RATELIMIT_FACTOR VAR_RATELIMIT_FACTOR
+%token VAR_IP_RATELIMIT_BACKOFF VAR_RATELIMIT_BACKOFF
 %token VAR_SEND_CLIENT_SUBNET VAR_CLIENT_SUBNET_ZONE
 %token VAR_CLIENT_SUBNET_ALWAYS_FORWARD VAR_CLIENT_SUBNET_OPCODE
 %token VAR_MAX_CLIENT_SUBNET_IPV4 VAR_MAX_CLIENT_SUBNET_IPV6
@@ -185,11 +188,12 @@ extern struct config_parser_state* cfg_parser;
 %token VAR_DYNLIB VAR_DYNLIB_FILE VAR_EDNS_CLIENT_STRING
 %token VAR_EDNS_CLIENT_STRING_OPCODE VAR_NSID
 %token VAR_ZONEMD_PERMISSIVE_MODE VAR_ZONEMD_CHECK VAR_ZONEMD_REJECT_ABSENCE
+%token VAR_RPZ_SIGNAL_NXDOMAIN_RA
 
 %%
 toplevelvars: /* empty */ | toplevelvars toplevelvar ;
 toplevelvar: serverstart contents_server | stubstart contents_stub |
-       forwardstart contents_forward | pythonstart contents_py | 
+       forwardstart contents_forward | pythonstart contents_py |
        rcstart contents_rc | dtstart contents_dt | viewstart contents_view |
        dnscstart contents_dnsc | cachedbstart contents_cachedb |
        ipsetstart contents_ipset | authstart contents_auth |
@@ -203,7 +207,7 @@ force_toplevel: VAR_FORCE_TOPLEVEL
        ;
 /* server: declaration */
 serverstart: VAR_SERVER
-       { 
+       {
                OUTYY(("\nP(server:)\n"));
        }
        ;
@@ -215,14 +219,14 @@ content_server: server_num_threads | server_verbosity | server_port |
        server_do_udp | server_do_tcp |
        server_tcp_mss | server_outgoing_tcp_mss | server_tcp_idle_timeout |
        server_tcp_keepalive | server_tcp_keepalive_timeout |
-       server_interface | server_chroot | server_username | 
+       server_interface | server_chroot | server_username |
        server_directory | server_logfile | server_pidfile |
        server_msg_cache_size | server_msg_cache_slabs |
-       server_num_queries_per_thread | server_rrset_cache_size | 
-       server_rrset_cache_slabs | server_outgoing_num_tcp | 
-       server_infra_host_ttl | server_infra_lame_ttl | 
+       server_num_queries_per_thread | server_rrset_cache_size |
+       server_rrset_cache_slabs | server_outgoing_num_tcp |
+       server_infra_host_ttl | server_infra_lame_ttl |
        server_infra_cache_slabs | server_infra_cache_numhosts |
-       server_infra_cache_lame_size | server_target_fetch_policy | 
+       server_infra_cache_lame_size | server_target_fetch_policy |
        server_harden_short_bufsize | server_harden_large_queries |
        server_do_not_query_address | server_hide_identity |
        server_hide_version | server_identity | server_version |
@@ -230,22 +234,22 @@ content_server: server_num_threads | server_verbosity | server_port |
        server_harden_glue | server_module_conf | server_trust_anchor_file |
        server_trust_anchor | server_val_override_date | server_bogus_ttl |
        server_val_clean_additional | server_val_permissive_mode |
-       server_incoming_num_tcp | server_msg_buffer_size | 
-       server_key_cache_size | server_key_cache_slabs | 
+       server_incoming_num_tcp | server_msg_buffer_size |
+       server_key_cache_size | server_key_cache_slabs |
        server_trusted_keys_file | server_val_nsec3_keysize_iterations |
        server_use_syslog | server_outgoing_interface | server_root_hints |
        server_do_not_query_localhost | server_cache_max_ttl |
        server_harden_dnssec_stripped | server_access_control |
        server_local_zone | server_local_data | server_interface_automatic |
-       server_statistics_interval | server_do_daemonize | 
+       server_statistics_interval | server_do_daemonize |
        server_use_caps_for_id | server_statistics_cumulative |
        server_outgoing_port_permit | server_outgoing_port_avoid |
        server_dlv_anchor_file | server_dlv_anchor | server_neg_cache_size |
        server_harden_referral_path | server_private_address |
-       server_private_domain | server_extended_statistics | 
-       server_local_data_ptr | server_jostle_timeout | 
-       server_unwanted_reply_threshold | server_log_time_ascii | 
-       server_domain_insecure | server_val_sig_skew_min | 
+       server_private_domain | server_extended_statistics |
+       server_local_data_ptr | server_jostle_timeout |
+       server_unwanted_reply_threshold | server_log_time_ascii |
+       server_domain_insecure | server_val_sig_skew_min |
        server_val_sig_skew_max | server_val_max_restart |
        server_cache_min_ttl | server_val_log_level |
        server_auto_trust_anchor_file | server_add_holddown |
@@ -269,9 +273,10 @@ content_server: server_num_threads | server_verbosity | server_port |
        server_ip_ratelimit_size | server_ratelimit_size |
        server_ratelimit_for_domain |
        server_ratelimit_below_domain | server_ratelimit_factor |
-       server_ip_ratelimit_factor | server_send_client_subnet |
-       server_client_subnet_zone | server_client_subnet_always_forward |
-       server_client_subnet_opcode |
+       server_ip_ratelimit_factor | server_ratelimit_backoff |
+       server_ip_ratelimit_backoff | server_outbound_msg_retry |
+       server_send_client_subnet | server_client_subnet_zone |
+       server_client_subnet_always_forward | server_client_subnet_opcode |
        server_max_client_subnet_ipv4 | server_max_client_subnet_ipv6 |
        server_min_client_subnet_ipv4 | server_min_client_subnet_ipv6 |
        server_max_ecs_tree_size_ipv4 | server_max_ecs_tree_size_ipv6 |
@@ -312,52 +317,55 @@ content_server: server_num_threads | server_verbosity | server_port |
 stubstart: VAR_STUB_ZONE
        {
                struct config_stub* s;
-               OUTYY(("\nP(stub_zone:)\n")); 
+               OUTYY(("\nP(stub_zone:)\n"));
                s = (struct config_stub*)calloc(1, sizeof(struct config_stub));
                if(s) {
                        s->next = cfg_parser->cfg->stubs;
                        cfg_parser->cfg->stubs = s;
-               } else 
+               } else {
                        yyerror("out of memory");
+               }
        }
        ;
-contents_stub: contents_stub content_stub 
+contents_stub: contents_stub content_stub
        | ;
 content_stub: stub_name | stub_host | stub_addr | stub_prime | stub_first |
-       stub_no_cache | stub_ssl_upstream
+       stub_no_cache | stub_ssl_upstream | stub_tcp_upstream
        ;
 forwardstart: VAR_FORWARD_ZONE
        {
                struct config_stub* s;
-               OUTYY(("\nP(forward_zone:)\n")); 
+               OUTYY(("\nP(forward_zone:)\n"));
                s = (struct config_stub*)calloc(1, sizeof(struct config_stub));
                if(s) {
                        s->next = cfg_parser->cfg->forwards;
                        cfg_parser->cfg->forwards = s;
-               } else 
+               } else {
                        yyerror("out of memory");
+               }
        }
        ;
-contents_forward: contents_forward content_forward 
+contents_forward: contents_forward content_forward
        | ;
 content_forward: forward_name | forward_host | forward_addr | forward_first |
-       forward_no_cache | forward_ssl_upstream
+       forward_no_cache | forward_ssl_upstream | forward_tcp_upstream
        ;
 viewstart: VAR_VIEW
        {
                struct config_view* s;
-               OUTYY(("\nP(view:)\n")); 
+               OUTYY(("\nP(view:)\n"));
                s = (struct config_view*)calloc(1, sizeof(struct config_view));
                if(s) {
                        s->next = cfg_parser->cfg->views;
                        if(s->next && !s->next->name)
                                yyerror("view without name");
                        cfg_parser->cfg->views = s;
-               } else 
+               } else {
                        yyerror("out of memory");
+               }
        }
        ;
-contents_view: contents_view content_view 
+contents_view: contents_view content_view
        | ;
 content_view: view_name | view_local_zone | view_local_data | view_first |
                view_response_ip | view_response_ip_data | view_local_data_ptr
@@ -365,7 +373,7 @@ content_view: view_name | view_local_zone | view_local_data | view_first |
 authstart: VAR_AUTH_ZONE
        {
                struct config_auth* s;
-               OUTYY(("\nP(auth_zone:)\n")); 
+               OUTYY(("\nP(auth_zone:)\n"));
                s = (struct config_auth*)calloc(1, sizeof(struct config_auth));
                if(s) {
                        s->next = cfg_parser->cfg->auths;
@@ -377,11 +385,12 @@ authstart: VAR_AUTH_ZONE
                        s->zonemd_check = 0;
                        s->zonemd_reject_absence = 0;
                        s->isrpz = 0;
-               } else 
+               } else {
                        yyerror("out of memory");
+               }
        }
        ;
-contents_auth: contents_auth content_auth 
+contents_auth: contents_auth content_auth
        | ;
 content_auth: auth_name | auth_zonefile | auth_master | auth_url |
        auth_for_downstream | auth_for_upstream | auth_fallback_enabled |
@@ -449,6 +458,15 @@ rpz_log_name: VAR_RPZ_LOG_NAME STRING_ARG
                cfg_parser->cfg->auths->rpz_log_name = $2;
        }
        ;
+rpz_signal_nxdomain_ra: VAR_RPZ_SIGNAL_NXDOMAIN_RA STRING_ARG
+       {
+               OUTYY(("P(rpz_signal_nxdomain_ra:%s)\n", $2));
+               if(strcmp($2, "yes") != 0 && strcmp($2, "no") != 0)
+                       yyerror("expected yes or no.");
+               else cfg_parser->cfg->auths->rpz_signal_nxdomain_ra = (strcmp($2, "yes")==0);
+               free($2);
+       }
+       ;
 
 rpzstart: VAR_RPZ
        {
@@ -463,37 +481,38 @@ rpzstart: VAR_RPZ
                        s->for_upstream = 0;
                        s->fallback_enabled = 0;
                        s->isrpz = 1;
-               } else 
+               } else {
                        yyerror("out of memory");
+               }
        }
        ;
 contents_rpz: contents_rpz content_rpz 
        | ;
 content_rpz: auth_name | auth_zonefile | rpz_tag | auth_master | auth_url |
           auth_allow_notify | rpz_action_override | rpz_cname_override |
-          rpz_log | rpz_log_name
+          rpz_log | rpz_log_name | rpz_signal_nxdomain_ra | auth_for_downstream
        ;
-server_num_threads: VAR_NUM_THREADS STRING_ARG 
-       { 
-               OUTYY(("P(server_num_threads:%s)\n", $2)); 
+server_num_threads: VAR_NUM_THREADS STRING_ARG
+       {
+               OUTYY(("P(server_num_threads:%s)\n", $2));
                if(atoi($2) == 0 && strcmp($2, "0") != 0)
                        yyerror("number expected");
                else cfg_parser->cfg->num_threads = atoi($2);
                free($2);
        }
        ;
-server_verbosity: VAR_VERBOSITY STRING_ARG 
-       { 
-               OUTYY(("P(server_verbosity:%s)\n", $2)); 
+server_verbosity: VAR_VERBOSITY STRING_ARG
+       {
+               OUTYY(("P(server_verbosity:%s)\n", $2));
                if(atoi($2) == 0 && strcmp($2, "0") != 0)
                        yyerror("number expected");
                else cfg_parser->cfg->verbosity = atoi($2);
                free($2);
        }
        ;
-server_statistics_interval: VAR_STATISTICS_INTERVAL STRING_ARG 
-       { 
-               OUTYY(("P(server_statistics_interval:%s)\n", $2)); 
+server_statistics_interval: VAR_STATISTICS_INTERVAL STRING_ARG
+       {
+               OUTYY(("P(server_statistics_interval:%s)\n", $2));
                if(strcmp($2, "") == 0 || strcmp($2, "0") == 0)
                        cfg_parser->cfg->stat_interval = 0;
                else if(atoi($2) == 0)
@@ -529,9 +548,9 @@ server_shm_enable: VAR_SHM_ENABLE STRING_ARG
                free($2);
        }
        ;
-server_shm_key: VAR_SHM_KEY STRING_ARG 
-       { 
-               OUTYY(("P(server_shm_key:%s)\n", $2)); 
+server_shm_key: VAR_SHM_KEY STRING_ARG
+       {
+               OUTYY(("P(server_shm_key:%s)\n", $2));
                if(strcmp($2, "") == 0 || strcmp($2, "0") == 0)
                        cfg_parser->cfg->shm_key = 0;
                else if(atoi($2) == 0)
@@ -704,7 +723,7 @@ server_interface: VAR_INTERFACE STRING_ARG
                OUTYY(("P(server_interface:%s)\n", $2));
                if(cfg_parser->cfg->num_ifs == 0)
                        cfg_parser->cfg->ifs = calloc(1, sizeof(char*));
-               else    cfg_parser->cfg->ifs = realloc(cfg_parser->cfg->ifs,
+               else cfg_parser->cfg->ifs = realloc(cfg_parser->cfg->ifs,
                                (cfg_parser->cfg->num_ifs+1)*sizeof(char*));
                if(!cfg_parser->cfg->ifs)
                        yyerror("out of memory");
@@ -717,8 +736,8 @@ server_outgoing_interface: VAR_OUTGOING_INTERFACE STRING_ARG
                OUTYY(("P(server_outgoing_interface:%s)\n", $2));
                if(cfg_parser->cfg->num_out_ifs == 0)
                        cfg_parser->cfg->out_ifs = calloc(1, sizeof(char*));
-               else    cfg_parser->cfg->out_ifs = realloc(
-                       cfg_parser->cfg->out_ifs, 
+               else cfg_parser->cfg->out_ifs = realloc(
+                       cfg_parser->cfg->out_ifs,
                        (cfg_parser->cfg->num_out_ifs+1)*sizeof(char*));
                if(!cfg_parser->cfg->out_ifs)
                        yyerror("out of memory");
@@ -739,7 +758,7 @@ server_outgoing_range: VAR_OUTGOING_RANGE STRING_ARG
 server_outgoing_port_permit: VAR_OUTGOING_PORT_PERMIT STRING_ARG
        {
                OUTYY(("P(server_outgoing_port_permit:%s)\n", $2));
-               if(!cfg_mark_ports($2, 1, 
+               if(!cfg_mark_ports($2, 1,
                        cfg_parser->cfg->outgoing_avail_ports, 65536))
                        yyerror("port number or range (\"low-high\") expected");
                free($2);
@@ -748,7 +767,7 @@ server_outgoing_port_permit: VAR_OUTGOING_PORT_PERMIT STRING_ARG
 server_outgoing_port_avoid: VAR_OUTGOING_PORT_AVOID STRING_ARG
        {
                OUTYY(("P(server_outgoing_port_avoid:%s)\n", $2));
-               if(!cfg_mark_ports($2, 0, 
+               if(!cfg_mark_ports($2, 0,
                        cfg_parser->cfg->outgoing_avail_ports, 65536))
                        yyerror("port number or range (\"low-high\") expected");
                free($2);
@@ -838,10 +857,10 @@ server_prefer_ip6: VAR_PREFER_IP6 STRING_ARG
 server_tcp_mss: VAR_TCP_MSS STRING_ARG
        {
                OUTYY(("P(server_tcp_mss:%s)\n", $2));
-                if(atoi($2) == 0 && strcmp($2, "0") != 0)
-                        yyerror("number expected");
-                else cfg_parser->cfg->tcp_mss = atoi($2);
-                free($2);
+               if(atoi($2) == 0 && strcmp($2, "0") != 0)
+                               yyerror("number expected");
+               else cfg_parser->cfg->tcp_mss = atoi($2);
+               free($2);
        }
        ;
 server_outgoing_tcp_mss: VAR_OUTGOING_TCP_MSS STRING_ARG
@@ -1141,23 +1160,23 @@ server_log_queries: VAR_LOG_QUERIES STRING_ARG
        }
        ;
 server_log_replies: VAR_LOG_REPLIES STRING_ARG
-  {
-       OUTYY(("P(server_log_replies:%s)\n", $2));
-       if(strcmp($2, "yes") != 0 && strcmp($2, "no") != 0)
-               yyerror("expected yes or no.");
-       else cfg_parser->cfg->log_replies = (strcmp($2, "yes")==0);
-       free($2);
-  }
-  ;
+       {
+               OUTYY(("P(server_log_replies:%s)\n", $2));
+               if(strcmp($2, "yes") != 0 && strcmp($2, "no") != 0)
+                       yyerror("expected yes or no.");
+               else cfg_parser->cfg->log_replies = (strcmp($2, "yes")==0);
+               free($2);
+       }
+       ;
 server_log_tag_queryreply: VAR_LOG_TAG_QUERYREPLY STRING_ARG
-  {
-       OUTYY(("P(server_log_tag_queryreply:%s)\n", $2));
-       if(strcmp($2, "yes") != 0 && strcmp($2, "no") != 0)
-               yyerror("expected yes or no.");
-       else cfg_parser->cfg->log_tag_queryreply = (strcmp($2, "yes")==0);
-       free($2);
-  }
-  ;
+       {
+               OUTYY(("P(server_log_tag_queryreply:%s)\n", $2));
+               if(strcmp($2, "yes") != 0 && strcmp($2, "no") != 0)
+                       yyerror("expected yes or no.");
+               else cfg_parser->cfg->log_tag_queryreply = (strcmp($2, "yes")==0);
+               free($2);
+       }
+       ;
 server_log_servfail: VAR_LOG_SERVFAIL STRING_ARG
        {
                OUTYY(("P(server_log_servfail:%s)\n", $2));
@@ -1168,14 +1187,14 @@ server_log_servfail: VAR_LOG_SERVFAIL STRING_ARG
        }
        ;
 server_log_local_actions: VAR_LOG_LOCAL_ACTIONS STRING_ARG
-  {
-       OUTYY(("P(server_log_local_actions:%s)\n", $2));
-       if(strcmp($2, "yes") != 0 && strcmp($2, "no") != 0)
-               yyerror("expected yes or no.");
-       else cfg_parser->cfg->log_local_actions = (strcmp($2, "yes")==0);
-       free($2);
-  }
-  ;
+       {
+               OUTYY(("P(server_log_local_actions:%s)\n", $2));
+               if(strcmp($2, "yes") != 0 && strcmp($2, "no") != 0)
+                       yyerror("expected yes or no.");
+               else cfg_parser->cfg->log_local_actions = (strcmp($2, "yes")==0);
+               free($2);
+       }
+       ;
 server_chroot: VAR_CHROOT STRING_ARG
        {
                OUTYY(("P(server_chroot:%s)\n", $2));
@@ -1209,7 +1228,7 @@ server_directory: VAR_DIRECTORY STRING_ARG
                                cfg_parser->chroot)) == 0)
                                d += strlen(cfg_parser->chroot);
                        if(d[0]) {
-                           if(chdir(d))
+                               if(chdir(d))
                                log_err("cannot chdir to directory: %s (%s)",
                                        d, strerror(errno));
                        }
@@ -1402,35 +1421,35 @@ server_so_sndbuf: VAR_SO_SNDBUF STRING_ARG
        }
        ;
 server_so_reuseport: VAR_SO_REUSEPORT STRING_ARG
-    {
-        OUTYY(("P(server_so_reuseport:%s)\n", $2));
-        if(strcmp($2, "yes") != 0 && strcmp($2, "no") != 0)
-            yyerror("expected yes or no.");
-        else cfg_parser->cfg->so_reuseport =
-            (strcmp($2, "yes")==0);
-        free($2);
-    }
-    ;
+       {
+               OUTYY(("P(server_so_reuseport:%s)\n", $2));
+               if(strcmp($2, "yes") != 0 && strcmp($2, "no") != 0)
+                       yyerror("expected yes or no.");
+               else cfg_parser->cfg->so_reuseport =
+                       (strcmp($2, "yes")==0);
+               free($2);
+       }
+       ;
 server_ip_transparent: VAR_IP_TRANSPARENT STRING_ARG
-    {
-        OUTYY(("P(server_ip_transparent:%s)\n", $2));
-        if(strcmp($2, "yes") != 0 && strcmp($2, "no") != 0)
-            yyerror("expected yes or no.");
-        else cfg_parser->cfg->ip_transparent =
-            (strcmp($2, "yes")==0);
-        free($2);
-    }
-    ;
+       {
+               OUTYY(("P(server_ip_transparent:%s)\n", $2));
+               if(strcmp($2, "yes") != 0 && strcmp($2, "no") != 0)
+                       yyerror("expected yes or no.");
+               else cfg_parser->cfg->ip_transparent =
+                       (strcmp($2, "yes")==0);
+               free($2);
+       }
+       ;
 server_ip_freebind: VAR_IP_FREEBIND STRING_ARG
-    {
-        OUTYY(("P(server_ip_freebind:%s)\n", $2));
-        if(strcmp($2, "yes") != 0 && strcmp($2, "no") != 0)
-            yyerror("expected yes or no.");
-        else cfg_parser->cfg->ip_freebind =
-            (strcmp($2, "yes")==0);
-        free($2);
-    }
-    ;
+       {
+               OUTYY(("P(server_ip_freebind:%s)\n", $2));
+               if(strcmp($2, "yes") != 0 && strcmp($2, "no") != 0)
+                       yyerror("expected yes or no.");
+               else cfg_parser->cfg->ip_freebind =
+                       (strcmp($2, "yes")==0);
+               free($2);
+       }
+       ;
 server_ip_dscp: VAR_IP_DSCP STRING_ARG
        {
                OUTYY(("P(server_ip_dscp:%s)\n", $2));
@@ -1488,9 +1507,9 @@ server_msg_cache_size: VAR_MSG_CACHE_SIZE STRING_ARG
 server_msg_cache_slabs: VAR_MSG_CACHE_SLABS STRING_ARG
        {
                OUTYY(("P(server_msg_cache_slabs:%s)\n", $2));
-               if(atoi($2) == 0)
+               if(atoi($2) == 0) {
                        yyerror("number expected");
-               else {
+               else {
                        cfg_parser->cfg->msg_cache_slabs = atoi($2);
                        if(!is_pow2(cfg_parser->cfg->msg_cache_slabs))
                                yyerror("must be a power of 2");
@@ -1539,7 +1558,7 @@ server_unblock_lan_zones: VAR_UNBLOCK_LAN_ZONES STRING_ARG
                OUTYY(("P(server_unblock_lan_zones:%s)\n", $2));
                if(strcmp($2, "yes") != 0 && strcmp($2, "no") != 0)
                        yyerror("expected yes or no.");
-               else cfg_parser->cfg->unblock_lan_zones = 
+               else cfg_parser->cfg->unblock_lan_zones =
                        (strcmp($2, "yes")==0);
                free($2);
        }
@@ -1549,7 +1568,7 @@ server_insecure_lan_zones: VAR_INSECURE_LAN_ZONES STRING_ARG
                OUTYY(("P(server_insecure_lan_zones:%s)\n", $2));
                if(strcmp($2, "yes") != 0 && strcmp($2, "no") != 0)
                        yyerror("expected yes or no.");
-               else cfg_parser->cfg->insecure_lan_zones = 
+               else cfg_parser->cfg->insecure_lan_zones =
                        (strcmp($2, "yes")==0);
                free($2);
        }
@@ -1565,9 +1584,9 @@ server_rrset_cache_size: VAR_RRSET_CACHE_SIZE STRING_ARG
 server_rrset_cache_slabs: VAR_RRSET_CACHE_SLABS STRING_ARG
        {
                OUTYY(("P(server_rrset_cache_slabs:%s)\n", $2));
-               if(atoi($2) == 0)
+               if(atoi($2) == 0) {
                        yyerror("number expected");
-               else {
+               else {
                        cfg_parser->cfg->rrset_cache_slabs = atoi($2);
                        if(!is_pow2(cfg_parser->cfg->rrset_cache_slabs))
                                yyerror("must be a power of 2");
@@ -1612,9 +1631,9 @@ server_infra_cache_lame_size: VAR_INFRA_CACHE_LAME_SIZE STRING_ARG
 server_infra_cache_slabs: VAR_INFRA_CACHE_SLABS STRING_ARG
        {
                OUTYY(("P(server_infra_cache_slabs:%s)\n", $2));
-               if(atoi($2) == 0)
+               if(atoi($2) == 0) {
                        yyerror("number expected");
-               else {
+               else {
                        cfg_parser->cfg->infra_cache_slabs = atoi($2);
                        if(!is_pow2(cfg_parser->cfg->infra_cache_slabs))
                                yyerror("must be a power of 2");
@@ -1653,7 +1672,7 @@ server_harden_short_bufsize: VAR_HARDEN_SHORT_BUFSIZE STRING_ARG
                OUTYY(("P(server_harden_short_bufsize:%s)\n", $2));
                if(strcmp($2, "yes") != 0 && strcmp($2, "no") != 0)
                        yyerror("expected yes or no.");
-               else cfg_parser->cfg->harden_short_bufsize = 
+               else cfg_parser->cfg->harden_short_bufsize =
                        (strcmp($2, "yes")==0);
                free($2);
        }
@@ -1663,7 +1682,7 @@ server_harden_large_queries: VAR_HARDEN_LARGE_QUERIES STRING_ARG
                OUTYY(("P(server_harden_large_queries:%s)\n", $2));
                if(strcmp($2, "yes") != 0 && strcmp($2, "no") != 0)
                        yyerror("expected yes or no.");
-               else cfg_parser->cfg->harden_large_queries = 
+               else cfg_parser->cfg->harden_large_queries =
                        (strcmp($2, "yes")==0);
                free($2);
        }
@@ -1673,7 +1692,7 @@ server_harden_glue: VAR_HARDEN_GLUE STRING_ARG
                OUTYY(("P(server_harden_glue:%s)\n", $2));
                if(strcmp($2, "yes") != 0 && strcmp($2, "no") != 0)
                        yyerror("expected yes or no.");
-               else cfg_parser->cfg->harden_glue = 
+               else cfg_parser->cfg->harden_glue =
                        (strcmp($2, "yes")==0);
                free($2);
        }
@@ -1683,7 +1702,7 @@ server_harden_dnssec_stripped: VAR_HARDEN_DNSSEC_STRIPPED STRING_ARG
                OUTYY(("P(server_harden_dnssec_stripped:%s)\n", $2));
                if(strcmp($2, "yes") != 0 && strcmp($2, "no") != 0)
                        yyerror("expected yes or no.");
-               else cfg_parser->cfg->harden_dnssec_stripped = 
+               else cfg_parser->cfg->harden_dnssec_stripped =
                        (strcmp($2, "yes")==0);
                free($2);
        }
@@ -1693,7 +1712,7 @@ server_harden_below_nxdomain: VAR_HARDEN_BELOW_NXDOMAIN STRING_ARG
                OUTYY(("P(server_harden_below_nxdomain:%s)\n", $2));
                if(strcmp($2, "yes") != 0 && strcmp($2, "no") != 0)
                        yyerror("expected yes or no.");
-               else cfg_parser->cfg->harden_below_nxdomain = 
+               else cfg_parser->cfg->harden_below_nxdomain =
                        (strcmp($2, "yes")==0);
                free($2);
        }
@@ -1703,7 +1722,7 @@ server_harden_referral_path: VAR_HARDEN_REFERRAL_PATH STRING_ARG
                OUTYY(("P(server_harden_referral_path:%s)\n", $2));
                if(strcmp($2, "yes") != 0 && strcmp($2, "no") != 0)
                        yyerror("expected yes or no.");
-               else cfg_parser->cfg->harden_referral_path = 
+               else cfg_parser->cfg->harden_referral_path =
                        (strcmp($2, "yes")==0);
                free($2);
        }
@@ -1713,7 +1732,7 @@ server_harden_algo_downgrade: VAR_HARDEN_ALGO_DOWNGRADE STRING_ARG
                OUTYY(("P(server_harden_algo_downgrade:%s)\n", $2));
                if(strcmp($2, "yes") != 0 && strcmp($2, "no") != 0)
                        yyerror("expected yes or no.");
-               else cfg_parser->cfg->harden_algo_downgrade = 
+               else cfg_parser->cfg->harden_algo_downgrade =
                        (strcmp($2, "yes")==0);
                free($2);
        }
@@ -1723,7 +1742,7 @@ server_use_caps_for_id: VAR_USE_CAPS_FOR_ID STRING_ARG
                OUTYY(("P(server_use_caps_for_id:%s)\n", $2));
                if(strcmp($2, "yes") != 0 && strcmp($2, "no") != 0)
                        yyerror("expected yes or no.");
-               else cfg_parser->cfg->use_caps_bits_for_id = 
+               else cfg_parser->cfg->use_caps_bits_for_id =
                        (strcmp($2, "yes")==0);
                free($2);
        }
@@ -1797,7 +1816,7 @@ server_do_not_query_localhost: VAR_DO_NOT_QUERY_LOCALHOST STRING_ARG
                OUTYY(("P(server_do_not_query_localhost:%s)\n", $2));
                if(strcmp($2, "yes") != 0 && strcmp($2, "no") != 0)
                        yyerror("expected yes or no.");
-               else cfg_parser->cfg->donotquery_localhost = 
+               else cfg_parser->cfg->donotquery_localhost =
                        (strcmp($2, "yes")==0);
                free($2);
        }
@@ -1808,8 +1827,8 @@ server_access_control: VAR_ACCESS_CONTROL STRING_ARG STRING_ARG
                if(strcmp($3, "deny")!=0 && strcmp($3, "refuse")!=0 &&
                        strcmp($3, "deny_non_local")!=0 &&
                        strcmp($3, "refuse_non_local")!=0 &&
-                       strcmp($3, "allow_setrd")!=0 && 
-                       strcmp($3, "allow")!=0 && 
+                       strcmp($3, "allow_setrd")!=0 &&
+                       strcmp($3, "allow")!=0 &&
                        strcmp($3, "allow_snoop")!=0) {
                        yyerror("expected deny, refuse, deny_non_local, "
                                "refuse_non_local, allow, allow_setrd or "
@@ -1835,7 +1854,7 @@ server_val_override_date: VAR_VAL_OVERRIDE_DATE STRING_ARG
                if(*$2 == '\0' || strcmp($2, "0") == 0) {
                        cfg_parser->cfg->val_date_override = 0;
                } else if(strlen($2) == 14) {
-                       cfg_parser->cfg->val_date_override = 
+                       cfg_parser->cfg->val_date_override =
                                cfg_convert_timeval($2);
                        if(!cfg_parser->cfg->val_date_override)
                                yyerror("bad date/time specification");
@@ -1927,7 +1946,7 @@ server_val_clean_additional: VAR_VAL_CLEAN_ADDITIONAL STRING_ARG
                OUTYY(("P(server_val_clean_additional:%s)\n", $2));
                if(strcmp($2, "yes") != 0 && strcmp($2, "no") != 0)
                        yyerror("expected yes or no.");
-               else cfg_parser->cfg->val_clean_additional = 
+               else cfg_parser->cfg->val_clean_additional =
                        (strcmp($2, "yes")==0);
                free($2);
        }
@@ -1937,7 +1956,7 @@ server_val_permissive_mode: VAR_VAL_PERMISSIVE_MODE STRING_ARG
                OUTYY(("P(server_val_permissive_mode:%s)\n", $2));
                if(strcmp($2, "yes") != 0 && strcmp($2, "no") != 0)
                        yyerror("expected yes or no.");
-               else cfg_parser->cfg->val_permissive_mode = 
+               else cfg_parser->cfg->val_permissive_mode =
                        (strcmp($2, "yes")==0);
                free($2);
        }
@@ -2114,9 +2133,9 @@ server_key_cache_size: VAR_KEY_CACHE_SIZE STRING_ARG
 server_key_cache_slabs: VAR_KEY_CACHE_SLABS STRING_ARG
        {
                OUTYY(("P(server_key_cache_slabs:%s)\n", $2));
-               if(atoi($2) == 0)
+               if(atoi($2) == 0) {
                        yyerror("number expected");
-               else {
+               else {
                        cfg_parser->cfg->key_cache_slabs = atoi($2);
                        if(!is_pow2(cfg_parser->cfg->key_cache_slabs))
                                yyerror("must be a power of 2");
@@ -2171,7 +2190,7 @@ server_local_zone: VAR_LOCAL_ZONE STRING_ARG STRING_ARG
                        free($3);
 #endif
                } else {
-                       if(!cfg_str2list_insert(&cfg_parser->cfg->local_zones, 
+                       if(!cfg_str2list_insert(&cfg_parser->cfg->local_zones,
                                $2, $3))
                                fatal_exit("out of memory adding local-zone");
                }
@@ -2379,19 +2398,18 @@ server_response_ip_tag: VAR_RESPONSE_IP_TAG STRING_ARG STRING_ARG
                }
        }
        ;
-server_ip_ratelimit: VAR_IP_RATELIMIT STRING_ARG 
-       { 
-               OUTYY(("P(server_ip_ratelimit:%s)\n", $2)); 
+server_ip_ratelimit: VAR_IP_RATELIMIT STRING_ARG
+       {
+               OUTYY(("P(server_ip_ratelimit:%s)\n", $2));
                if(atoi($2) == 0 && strcmp($2, "0") != 0)
                        yyerror("number expected");
                else cfg_parser->cfg->ip_ratelimit = atoi($2);
                free($2);
        }
        ;
-
-server_ratelimit: VAR_RATELIMIT STRING_ARG 
-       { 
-               OUTYY(("P(server_ratelimit:%s)\n", $2)); 
+server_ratelimit: VAR_RATELIMIT STRING_ARG
+       {
+               OUTYY(("P(server_ratelimit:%s)\n", $2));
                if(atoi($2) == 0 && strcmp($2, "0") != 0)
                        yyerror("number expected");
                else cfg_parser->cfg->ratelimit = atoi($2);
@@ -2399,13 +2417,13 @@ server_ratelimit: VAR_RATELIMIT STRING_ARG
        }
        ;
 server_ip_ratelimit_size: VAR_IP_RATELIMIT_SIZE STRING_ARG
-  {
-       OUTYY(("P(server_ip_ratelimit_size:%s)\n", $2));
-       if(!cfg_parse_memsize($2, &cfg_parser->cfg->ip_ratelimit_size))
-               yyerror("memory size expected");
-       free($2);
-  }
-  ;
+       {
+               OUTYY(("P(server_ip_ratelimit_size:%s)\n", $2));
+               if(!cfg_parse_memsize($2, &cfg_parser->cfg->ip_ratelimit_size))
+                       yyerror("memory size expected");
+               free($2);
+       }
+       ;
 server_ratelimit_size: VAR_RATELIMIT_SIZE STRING_ARG
        {
                OUTYY(("P(server_ratelimit_size:%s)\n", $2));
@@ -2415,24 +2433,24 @@ server_ratelimit_size: VAR_RATELIMIT_SIZE STRING_ARG
        }
        ;
 server_ip_ratelimit_slabs: VAR_IP_RATELIMIT_SLABS STRING_ARG
-  {
-       OUTYY(("P(server_ip_ratelimit_slabs:%s)\n", $2));
-       if(atoi($2) == 0)
-               yyerror("number expected");
-       else {
-               cfg_parser->cfg->ip_ratelimit_slabs = atoi($2);
-               if(!is_pow2(cfg_parser->cfg->ip_ratelimit_slabs))
-                       yyerror("must be a power of 2");
-       }
-       free($2);
-  }
-  ;
+       {
+               OUTYY(("P(server_ip_ratelimit_slabs:%s)\n", $2));
+               if(atoi($2) == 0) {
+                       yyerror("number expected");
+               } else {
+                       cfg_parser->cfg->ip_ratelimit_slabs = atoi($2);
+                       if(!is_pow2(cfg_parser->cfg->ip_ratelimit_slabs))
+                               yyerror("must be a power of 2");
+               }
+               free($2);
+       }
+       ;
 server_ratelimit_slabs: VAR_RATELIMIT_SLABS STRING_ARG
        {
                OUTYY(("P(server_ratelimit_slabs:%s)\n", $2));
-               if(atoi($2) == 0)
+               if(atoi($2) == 0) {
                        yyerror("number expected");
-               else {
+               else {
                        cfg_parser->cfg->ratelimit_slabs = atoi($2);
                        if(!is_pow2(cfg_parser->cfg->ratelimit_slabs))
                                yyerror("must be a power of 2");
@@ -2470,42 +2488,71 @@ server_ratelimit_below_domain: VAR_RATELIMIT_BELOW_DOMAIN STRING_ARG STRING_ARG
                }
        }
        ;
-server_ip_ratelimit_factor: VAR_IP_RATELIMIT_FACTOR STRING_ARG 
-  { 
-       OUTYY(("P(server_ip_ratelimit_factor:%s)\n", $2)); 
-       if(atoi($2) == 0 && strcmp($2, "0") != 0)
-               yyerror("number expected");
-       else cfg_parser->cfg->ip_ratelimit_factor = atoi($2);
-       free($2);
+server_ip_ratelimit_factor: VAR_IP_RATELIMIT_FACTOR STRING_ARG
+       {
+               OUTYY(("P(server_ip_ratelimit_factor:%s)\n", $2));
+               if(atoi($2) == 0 && strcmp($2, "0") != 0)
+                       yyerror("number expected");
+               else cfg_parser->cfg->ip_ratelimit_factor = atoi($2);
+               free($2);
        }
        ;
-server_ratelimit_factor: VAR_RATELIMIT_FACTOR STRING_ARG 
-       { 
-               OUTYY(("P(server_ratelimit_factor:%s)\n", $2)); 
+server_ratelimit_factor: VAR_RATELIMIT_FACTOR STRING_ARG
+       {
+               OUTYY(("P(server_ratelimit_factor:%s)\n", $2));
                if(atoi($2) == 0 && strcmp($2, "0") != 0)
                        yyerror("number expected");
                else cfg_parser->cfg->ratelimit_factor = atoi($2);
                free($2);
        }
        ;
-server_low_rtt: VAR_LOW_RTT STRING_ARG 
-       { 
+server_ip_ratelimit_backoff: VAR_IP_RATELIMIT_BACKOFF STRING_ARG
+       {
+               OUTYY(("P(server_ip_ratelimit_backoff:%s)\n", $2));
+               if(strcmp($2, "yes") != 0 && strcmp($2, "no") != 0)
+                       yyerror("expected yes or no.");
+               else cfg_parser->cfg->ip_ratelimit_backoff =
+                       (strcmp($2, "yes")==0);
+               free($2);
+       }
+       ;
+server_ratelimit_backoff: VAR_RATELIMIT_BACKOFF STRING_ARG
+       {
+               OUTYY(("P(server_ratelimit_backoff:%s)\n", $2));
+               if(strcmp($2, "yes") != 0 && strcmp($2, "no") != 0)
+                       yyerror("expected yes or no.");
+               else cfg_parser->cfg->ratelimit_backoff =
+                       (strcmp($2, "yes")==0);
+               free($2);
+       }
+       ;
+server_outbound_msg_retry: VAR_OUTBOUND_MSG_RETRY STRING_ARG
+       {
+               OUTYY(("P(server_outbound_msg_retry:%s)\n", $2));
+               if(atoi($2) == 0 && strcmp($2, "0") != 0)
+                       yyerror("number expected");
+               else cfg_parser->cfg->outbound_msg_retry = atoi($2);
+               free($2);
+       }
+       ;
+server_low_rtt: VAR_LOW_RTT STRING_ARG
+       {
                OUTYY(("P(low-rtt option is deprecated, use fast-server-num instead)\n"));
                free($2);
        }
        ;
-server_fast_server_num: VAR_FAST_SERVER_NUM STRING_ARG 
-       { 
-               OUTYY(("P(server_fast_server_num:%s)\n", $2)); 
+server_fast_server_num: VAR_FAST_SERVER_NUM STRING_ARG
+       {
+               OUTYY(("P(server_fast_server_num:%s)\n", $2));
                if(atoi($2) <= 0)
                        yyerror("number expected");
                else cfg_parser->cfg->fast_server_num = atoi($2);
                free($2);
        }
        ;
-server_fast_server_permil: VAR_FAST_SERVER_PERMIL STRING_ARG 
-       { 
-               OUTYY(("P(server_fast_server_permil:%s)\n", $2)); 
+server_fast_server_permil: VAR_FAST_SERVER_PERMIL STRING_ARG
+       {
+               OUTYY(("P(server_fast_server_permil:%s)\n", $2));
                if(atoi($2) == 0 && strcmp($2, "0") != 0)
                        yyerror("number expected");
                else cfg_parser->cfg->fast_server_permil = atoi($2);
@@ -2517,7 +2564,7 @@ server_qname_minimisation: VAR_QNAME_MINIMISATION STRING_ARG
                OUTYY(("P(server_qname_minimisation:%s)\n", $2));
                if(strcmp($2, "yes") != 0 && strcmp($2, "no") != 0)
                        yyerror("expected yes or no.");
-               else cfg_parser->cfg->qname_minimisation = 
+               else cfg_parser->cfg->qname_minimisation =
                        (strcmp($2, "yes")==0);
                free($2);
        }
@@ -2527,7 +2574,7 @@ server_qname_minimisation_strict: VAR_QNAME_MINIMISATION_STRICT STRING_ARG
                OUTYY(("P(server_qname_minimisation_strict:%s)\n", $2));
                if(strcmp($2, "yes") != 0 && strcmp($2, "no") != 0)
                        yyerror("expected yes or no.");
-               else cfg_parser->cfg->qname_minimisation_strict = 
+               else cfg_parser->cfg->qname_minimisation_strict =
                        (strcmp($2, "yes")==0);
                free($2);
        }
@@ -2716,17 +2763,27 @@ stub_ssl_upstream: VAR_STUB_SSL_UPSTREAM STRING_ARG
                OUTYY(("P(stub-ssl-upstream:%s)\n", $2));
                if(strcmp($2, "yes") != 0 && strcmp($2, "no") != 0)
                        yyerror("expected yes or no.");
-               else cfg_parser->cfg->stubs->ssl_upstream = 
+               else cfg_parser->cfg->stubs->ssl_upstream =
                        (strcmp($2, "yes")==0);
                free($2);
        }
        ;
+stub_tcp_upstream: VAR_STUB_TCP_UPSTREAM STRING_ARG
+        {
+                OUTYY(("P(stub-tcp-upstream:%s)\n", $2));
+                if(strcmp($2, "yes") != 0 && strcmp($2, "no") != 0)
+                        yyerror("expected yes or no.");
+                else cfg_parser->cfg->stubs->tcp_upstream =
+                        (strcmp($2, "yes")==0);
+                free($2);
+        }
+        ;
 stub_prime: VAR_STUB_PRIME STRING_ARG
        {
                OUTYY(("P(stub-prime:%s)\n", $2));
                if(strcmp($2, "yes") != 0 && strcmp($2, "no") != 0)
                        yyerror("expected yes or no.");
-               else cfg_parser->cfg->stubs->isprime = 
+               else cfg_parser->cfg->stubs->isprime =
                        (strcmp($2, "yes")==0);
                free($2);
        }
@@ -2778,11 +2835,21 @@ forward_ssl_upstream: VAR_FORWARD_SSL_UPSTREAM STRING_ARG
                OUTYY(("P(forward-ssl-upstream:%s)\n", $2));
                if(strcmp($2, "yes") != 0 && strcmp($2, "no") != 0)
                        yyerror("expected yes or no.");
-               else cfg_parser->cfg->forwards->ssl_upstream = 
+               else cfg_parser->cfg->forwards->ssl_upstream =
                        (strcmp($2, "yes")==0);
                free($2);
        }
        ;
+forward_tcp_upstream: VAR_FORWARD_TCP_UPSTREAM STRING_ARG
+        {
+                OUTYY(("P(forward-tcp-upstream:%s)\n", $2));
+                if(strcmp($2, "yes") != 0 && strcmp($2, "no") != 0)
+                        yyerror("expected yes or no.");
+                else cfg_parser->cfg->forwards->tcp_upstream =
+                        (strcmp($2, "yes")==0);
+                free($2);
+        }
+        ;
 auth_name: VAR_NAME STRING_ARG
        {
                OUTYY(("P(name:%s)\n", $2));
@@ -2922,7 +2989,7 @@ view_local_zone: VAR_LOCAL_ZONE STRING_ARG STRING_ARG
 #endif
                } else {
                        if(!cfg_str2list_insert(
-                               &cfg_parser->cfg->views->local_zones, 
+                               &cfg_parser->cfg->views->local_zones,
                                $2, $3))
                                fatal_exit("out of memory adding local-zone");
                }
@@ -2979,11 +3046,11 @@ view_first: VAR_VIEW_FIRST STRING_ARG
        }
        ;
 rcstart: VAR_REMOTE_CONTROL
-       { 
-               OUTYY(("\nP(remote-control:)\n")); 
+       {
+               OUTYY(("\nP(remote-control:)\n"));
        }
        ;
-contents_rc: contents_rc content_rc 
+contents_rc: contents_rc content_rc
        | ;
 content_rc: rc_control_enable | rc_control_interface | rc_control_port |
        rc_server_key_file | rc_server_cert_file | rc_control_key_file |
@@ -2994,7 +3061,7 @@ rc_control_enable: VAR_CONTROL_ENABLE STRING_ARG
                OUTYY(("P(control_enable:%s)\n", $2));
                if(strcmp($2, "yes") != 0 && strcmp($2, "no") != 0)
                        yyerror("expected yes or no.");
-               else cfg_parser->cfg->remote_control_enable = 
+               else cfg_parser->cfg->remote_control_enable =
                        (strcmp($2, "yes")==0);
                free($2);
        }
@@ -3233,8 +3300,8 @@ dt_dnstap_log_forwarder_response_messages: VAR_DNSTAP_LOG_FORWARDER_RESPONSE_MES
        }
        ;
 pythonstart: VAR_PYTHON
-       { 
-               OUTYY(("\nP(python:)\n")); 
+       {
+               OUTYY(("\nP(python:)\n"));
        }
        ;
 contents_py: contents_py content_py
@@ -3365,44 +3432,44 @@ dnsc_dnscrypt_secret_key: VAR_DNSCRYPT_SECRET_KEY STRING_ARG
        ;
 dnsc_dnscrypt_shared_secret_cache_size: VAR_DNSCRYPT_SHARED_SECRET_CACHE_SIZE STRING_ARG
   {
-       OUTYY(("P(dnscrypt_shared_secret_cache_size:%s)\n", $2));
-       if(!cfg_parse_memsize($2, &cfg_parser->cfg->dnscrypt_shared_secret_cache_size))
-               yyerror("memory size expected");
-       free($2);
+       OUTYY(("P(dnscrypt_shared_secret_cache_size:%s)\n", $2));
+       if(!cfg_parse_memsize($2, &cfg_parser->cfg->dnscrypt_shared_secret_cache_size))
+               yyerror("memory size expected");
+       free($2);
   }
   ;
 dnsc_dnscrypt_shared_secret_cache_slabs: VAR_DNSCRYPT_SHARED_SECRET_CACHE_SLABS STRING_ARG
   {
-       OUTYY(("P(dnscrypt_shared_secret_cache_slabs:%s)\n", $2));
-       if(atoi($2) == 0)
-               yyerror("number expected");
-       else {
-               cfg_parser->cfg->dnscrypt_shared_secret_cache_slabs = atoi($2);
-               if(!is_pow2(cfg_parser->cfg->dnscrypt_shared_secret_cache_slabs))
-                       yyerror("must be a power of 2");
-       }
-       free($2);
+       OUTYY(("P(dnscrypt_shared_secret_cache_slabs:%s)\n", $2));
+       if(atoi($2) == 0) {
+               yyerror("number expected");
+       else {
+               cfg_parser->cfg->dnscrypt_shared_secret_cache_slabs = atoi($2);
+               if(!is_pow2(cfg_parser->cfg->dnscrypt_shared_secret_cache_slabs))
+                       yyerror("must be a power of 2");
+       }
+       free($2);
   }
   ;
 dnsc_dnscrypt_nonce_cache_size: VAR_DNSCRYPT_NONCE_CACHE_SIZE STRING_ARG
   {
-       OUTYY(("P(dnscrypt_nonce_cache_size:%s)\n", $2));
-       if(!cfg_parse_memsize($2, &cfg_parser->cfg->dnscrypt_nonce_cache_size))
-               yyerror("memory size expected");
-       free($2);
+       OUTYY(("P(dnscrypt_nonce_cache_size:%s)\n", $2));
+       if(!cfg_parse_memsize($2, &cfg_parser->cfg->dnscrypt_nonce_cache_size))
+               yyerror("memory size expected");
+       free($2);
   }
   ;
 dnsc_dnscrypt_nonce_cache_slabs: VAR_DNSCRYPT_NONCE_CACHE_SLABS STRING_ARG
   {
-       OUTYY(("P(dnscrypt_nonce_cache_slabs:%s)\n", $2));
-       if(atoi($2) == 0)
-               yyerror("number expected");
-       else {
-               cfg_parser->cfg->dnscrypt_nonce_cache_slabs = atoi($2);
-               if(!is_pow2(cfg_parser->cfg->dnscrypt_nonce_cache_slabs))
-                       yyerror("must be a power of 2");
-       }
-       free($2);
+       OUTYY(("P(dnscrypt_nonce_cache_slabs:%s)\n", $2));
+       if(atoi($2) == 0) {
+               yyerror("number expected");
+       else {
+               cfg_parser->cfg->dnscrypt_nonce_cache_slabs = atoi($2);
+               if(!is_pow2(cfg_parser->cfg->dnscrypt_nonce_cache_slabs))
+                       yyerror("must be a power of 2");
+       }
+       free($2);
   }
   ;
 cachedbstart: VAR_CACHEDB
index 5f297b5..fe21cfb 100644 (file)
@@ -796,7 +796,10 @@ calc_edns_field_size(struct edns_data* edns)
        struct edns_option* opt;
        if(!edns || !edns->edns_present)
                return 0;
-       for(opt = edns->opt_list; opt; opt = opt->next) {
+       for(opt = edns->opt_list_inplace_cb_out; opt; opt = opt->next) {
+               rdatalen += 4 + opt->opt_len;
+       }
+       for(opt = edns->opt_list_out; opt; opt = opt->next) {
                rdatalen += 4 + opt->opt_len;
        }
        /* domain root '.' + type + class + ttl + rdatalen */
@@ -827,7 +830,17 @@ attach_edns_record_max_msg_sz(sldns_buffer* pkt, struct edns_data* edns,
        rdatapos = sldns_buffer_position(pkt);
        sldns_buffer_write_u16(pkt, 0); /* rdatalen */
        /* write rdata */
-       for(opt=edns->opt_list; opt; opt=opt->next) {
+       for(opt=edns->opt_list_inplace_cb_out; opt; opt=opt->next) {
+               if (opt->opt_code == LDNS_EDNS_PADDING) {
+                       padding_option = opt;
+                       continue;
+               }
+               sldns_buffer_write_u16(pkt, opt->opt_code);
+               sldns_buffer_write_u16(pkt, opt->opt_len);
+               if(opt->opt_len != 0)
+                       sldns_buffer_write(pkt, opt->opt_data, opt->opt_len);
+       }
+       for(opt=edns->opt_list_out; opt; opt=opt->next) {
                if (opt->opt_code == LDNS_EDNS_PADDING) {
                        padding_option = opt;
                        continue;
@@ -860,8 +873,7 @@ attach_edns_record_max_msg_sz(sldns_buffer* pkt, struct edns_data* edns,
                        sldns_buffer_skip(pkt, pad_sz);
                }
        }
-       if(edns->opt_list)
-               sldns_buffer_write_u16_at(pkt, rdatapos, 
+       sldns_buffer_write_u16_at(pkt, rdatapos, 
                        sldns_buffer_position(pkt)-rdatapos-2);
        sldns_buffer_flip(pkt);
 }
index 6ee5559..a600a8c 100644 (file)
  * Routines for message parsing a packet buffer to a descriptive structure.
  */
 #include "config.h"
+#include "util/config_file.h"
 #include "util/data/msgparse.h"
 #include "util/data/msgreply.h"
 #include "util/data/dname.h"
 #include "util/data/packed_rrset.h"
+#include "util/netevent.h"
 #include "util/storage/lookup3.h"
 #include "util/regional.h"
 #include "sldns/rrdef.h"
@@ -938,11 +940,40 @@ parse_packet(sldns_buffer* pkt, struct msg_parse* msg, struct regional* region)
        return 0;
 }
 
+static int
+edns_opt_list_append_keepalive(struct edns_option** list, int msec,
+               struct regional* region)
+{
+       uint8_t data[2]; /* For keepalive value */
+       data[0] = (uint8_t)((msec >> 8) & 0xff);
+       data[1] = (uint8_t)(msec & 0xff);
+       return edns_opt_list_append(list, LDNS_EDNS_KEEPALIVE, sizeof(data),
+                       data, region);
+}
+
 /** parse EDNS options from EDNS wireformat rdata */
 static int
-parse_edns_options(uint8_t* rdata_ptr, size_t rdata_len,
-       struct edns_data* edns, struct regional* region)
+parse_edns_options_from_query(uint8_t* rdata_ptr, size_t rdata_len,
+       struct edns_data* edns, struct config_file* cfg, struct comm_point* c,
+       struct regional* region)
 {
+       /* To respond with a Keepalive option, the client connection must have
+        * received one message with a TCP Keepalive EDNS option, and that
+        * option must have 0 length data. Subsequent messages sent on that
+        * connection will have a TCP Keepalive option.
+        *
+        * In the if-statement below, the option is added unsolicited. This
+        * means that the client has sent an KEEPALIVE option earlier. We know
+        * here this is true, because c->tcp_keepalive is set.
+        */
+       if (cfg && cfg->do_tcp_keepalive && c && c->type != comm_udp && c->tcp_keepalive) {
+               if(!edns_opt_list_append_keepalive(&edns->opt_list_out,
+                                       c->tcp_timeout_msec / 100, region)) {
+                       log_err("out of memory");
+                       return LDNS_RCODE_SERVFAIL;
+               }
+       }
+
        /* while still more options, and have code+len to read */
        /* ignores partial content (i.e. rdata len 3) */
        while(rdata_len >= 4) {
@@ -952,20 +983,81 @@ parse_edns_options(uint8_t* rdata_ptr, size_t rdata_len,
                rdata_len -= 4;
                if(opt_len > rdata_len)
                        break; /* option code partial */
-               if(!edns_opt_append(edns, region, opt_code, opt_len,
-                       rdata_ptr)) {
+
+               /* handle parse time edns options here */
+               switch(opt_code) {
+               case LDNS_EDNS_NSID:
+                       if (!cfg || !cfg->nsid)
+                               break;
+                       if(!edns_opt_list_append(&edns->opt_list_out,
+                                               LDNS_EDNS_NSID, cfg->nsid_len,
+                                               cfg->nsid, region)) {
+                               log_err("out of memory");
+                               return LDNS_RCODE_SERVFAIL;
+                       }
+                       break;
+
+               case LDNS_EDNS_KEEPALIVE:
+                       /* To respond with a Keepalive option, the client
+                        * connection must have received one message with a TCP
+                        * Keepalive EDNS option, and that option must have 0
+                        * length data. Subsequent messages sent on that
+                        * connection will have a TCP Keepalive option.
+                        *
+                        * This should be the first time the client sends this
+                        * option, so c->tcp_keepalive is not set.
+                        * Besides adding the reply KEEPALIVE option, 
+                        * c->tcp_keepalive will be set so that the
+                        * option will be added unsolicited in subsequent
+                        * responses (see the comment above the if-statement
+                        * at the start of this function).
+                        */
+                       if (!cfg || !cfg->do_tcp_keepalive || !c ||
+                                       c->type == comm_udp || c->tcp_keepalive)
+                               break;
+                       if(opt_len) {
+                               verbose(VERB_ALGO, "query with bad edns keepalive.");
+                               return LDNS_RCODE_FORMERR;
+                       }
+                       if(!edns_opt_list_append_keepalive(&edns->opt_list_out,
+                                               c->tcp_timeout_msec / 100,
+                                               region)) {
+                               log_err("out of memory");
+                               return LDNS_RCODE_SERVFAIL;
+                       }
+                       c->tcp_keepalive = 1;
+                       break;
+
+               case LDNS_EDNS_PADDING:
+                       if(!cfg || !cfg->pad_responses ||
+                                       !c || c->type != comm_tcp ||!c->ssl)
+                               break;
+                       if(!edns_opt_list_append(&edns->opt_list_out,
+                                               LDNS_EDNS_PADDING,
+                                               0, NULL, region)) {
+                               log_err("out of memory");
+                               return LDNS_RCODE_SERVFAIL;
+                       }
+                       edns->padding_block_size = cfg->pad_responses_block_size;
+                       break;
+
+               default:
+                       break;
+               }
+               if(!edns_opt_list_append(&edns->opt_list_in,
+                               opt_code, opt_len, rdata_ptr, region)) {
                        log_err("out of memory");
-                       return 0;
+                       return LDNS_RCODE_SERVFAIL;
                }
                rdata_ptr += opt_len;
                rdata_len -= opt_len;
        }
-       return 1;
+       return LDNS_RCODE_NOERROR;
 }
 
 int 
-parse_extract_edns(struct msg_parse* msg, struct edns_data* edns,
-       struct regional* region)
+parse_extract_edns_from_response_msg(struct msg_parse* msg,
+       struct edns_data* edns, struct regional* region)
 {
        struct rrset_parse* rrset = msg->rrset_first;
        struct rrset_parse* prev = 0;
@@ -1019,18 +1111,35 @@ parse_extract_edns(struct msg_parse* msg, struct edns_data* edns,
        edns->edns_version = found->rr_last->ttl_data[1];
        edns->bits = sldns_read_uint16(&found->rr_last->ttl_data[2]);
        edns->udp_size = ntohs(found->rrset_class);
-       edns->opt_list = NULL;
+       edns->opt_list_in = NULL;
+       edns->opt_list_out = NULL;
+       edns->opt_list_inplace_cb_out = NULL;
        edns->padding_block_size = 0;
 
        /* take the options */
        rdata_len = found->rr_first->size-2;
        rdata_ptr = found->rr_first->ttl_data+6;
-       if(!parse_edns_options(rdata_ptr, rdata_len, edns, region))
-               return 0;
 
-       /* ignore rrsigs */
+       /* while still more options, and have code+len to read */
+       /* ignores partial content (i.e. rdata len 3) */
+       while(rdata_len >= 4) {
+               uint16_t opt_code = sldns_read_uint16(rdata_ptr);
+               uint16_t opt_len = sldns_read_uint16(rdata_ptr+2);
+               rdata_ptr += 4;
+               rdata_len -= 4;
+               if(opt_len > rdata_len)
+                       break; /* option code partial */
 
-       return 0;
+               if(!edns_opt_list_append(&edns->opt_list_in,
+                               opt_code, opt_len, rdata_ptr, region)) {
+                       log_err("out of memory");
+                       break;
+               }
+               rdata_ptr += opt_len;
+               rdata_len -= opt_len;
+       }
+       /* ignore rrsigs */
+       return LDNS_RCODE_NOERROR;
 }
 
 /** skip RR in packet */
@@ -1060,8 +1169,8 @@ skip_pkt_rrs(sldns_buffer* pkt, int num)
 }
 
 int 
-parse_edns_from_pkt(sldns_buffer* pkt, struct edns_data* edns,
-       struct regional* region)
+parse_edns_from_query_pkt(sldns_buffer* pkt, struct edns_data* edns,
+       struct config_file* cfg, struct comm_point* c, struct regional* region)
 {
        size_t rdata_len;
        uint8_t* rdata_ptr;
@@ -1093,7 +1202,9 @@ parse_edns_from_pkt(sldns_buffer* pkt, struct edns_data* edns,
        edns->ext_rcode = sldns_buffer_read_u8(pkt); /* ttl used for bits */
        edns->edns_version = sldns_buffer_read_u8(pkt);
        edns->bits = sldns_buffer_read_u16(pkt);
-       edns->opt_list = NULL;
+       edns->opt_list_in = NULL;
+       edns->opt_list_out = NULL;
+       edns->opt_list_inplace_cb_out = NULL;
        edns->padding_block_size = 0;
 
        /* take the options */
@@ -1101,12 +1212,9 @@ parse_edns_from_pkt(sldns_buffer* pkt, struct edns_data* edns,
        if(sldns_buffer_remaining(pkt) < rdata_len)
                return LDNS_RCODE_FORMERR;
        rdata_ptr = sldns_buffer_current(pkt);
-       if(!parse_edns_options(rdata_ptr, rdata_len, edns, region))
-               return LDNS_RCODE_SERVFAIL;
-
        /* ignore rrsigs */
-
-       return 0;
+       return parse_edns_options_from_query(rdata_ptr, rdata_len, edns, cfg,
+                       c, region);
 }
 
 void
index d2fd9c8..4c0559a 100644 (file)
@@ -70,6 +70,8 @@ struct rrset_parse;
 struct rr_parse;
 struct regional;
 struct edns_option;
+struct config_file;
+struct comm_point;
 
 /** number of buckets in parse rrset hash table. Must be power of 2. */
 #define PARSE_TABLE_SIZE 32
@@ -225,8 +227,15 @@ struct edns_data {
        uint16_t bits;
        /** UDP reassembly size. */
        uint16_t udp_size;
-       /** rdata element list, or NULL if none */
-       struct edns_option* opt_list;
+       /** rdata element list of options of an incoming packet created at
+        * parse time, or NULL if none */
+       struct edns_option* opt_list_in;
+       /** rdata element list of options to encode for outgoing packets,
+        * or NULL if none */
+       struct edns_option* opt_list_out;
+       /** rdata element list of outgoing edns options from modules
+        * or NULL if none */
+       struct edns_option* opt_list_inplace_cb_out;
        /** block size to pad */
        uint16_t padding_block_size;
 };
@@ -281,8 +290,8 @@ int parse_packet(struct sldns_buffer* pkt, struct msg_parse* msg,
  * @return: 0 on success. or an RCODE on an error.
  *     RCODE formerr if OPT in wrong section, and so on.
  */
-int parse_extract_edns(struct msg_parse* msg, struct edns_data* edns,
-       struct regional* region);
+int parse_extract_edns_from_response_msg(struct msg_parse* msg,
+       struct edns_data* edns, struct regional* region);
 
 /**
  * If EDNS data follows a query section, extract it and initialize edns struct.
@@ -290,12 +299,14 @@ int parse_extract_edns(struct msg_parse* msg, struct edns_data* edns,
  *     section. At end, right after EDNS data or no movement if failed.
  * @param edns: the edns data allocated by the caller. Does not have to be
  *     initialised.
+ * @param cfg: the configuration (with nsid value etc.)
+ * @param c: commpoint to determine transport (if needed)
  * @param region: region to alloc results in (edns option contents)
  * @return: 0 on success, or an RCODE on error.
  *     RCODE formerr if OPT is badly formatted and so on.
  */
-int parse_edns_from_pkt(struct sldns_buffer* pkt, struct edns_data* edns,
-       struct regional* region);
+int parse_edns_from_query_pkt(struct sldns_buffer* pkt, struct edns_data* edns,
+       struct config_file* cfg, struct comm_point* c, struct regional* region);
 
 /**
  * Calculate hash value for rrset in packet.
index 00272fd..ec46e47 100644 (file)
@@ -166,6 +166,32 @@ reply_info_alloc_rrset_keys(struct reply_info* rep, struct alloc_cache* alloc,
        return 1;
 }
 
+struct reply_info *
+make_new_reply_info(const struct reply_info* rep, struct regional* region,
+       size_t an_numrrsets, size_t copy_rrsets)
+{
+       struct reply_info* new_rep;
+       size_t i;
+
+       /* create a base struct.  we specify 'insecure' security status as
+        * the modified response won't be DNSSEC-valid.  In our faked response
+        * the authority and additional sections will be empty (except possible
+        * EDNS0 OPT RR in the additional section appended on sending it out),
+        * so the total number of RRsets is an_numrrsets. */
+       new_rep = construct_reply_info_base(region, rep->flags,
+               rep->qdcount, rep->ttl, rep->prefetch_ttl,
+               rep->serve_expired_ttl, an_numrrsets, 0, 0, an_numrrsets,
+               sec_status_insecure);
+       if(!new_rep)
+               return NULL;
+       if(!reply_info_alloc_rrset_keys(new_rep, NULL, region))
+               return NULL;
+       for(i=0; i<copy_rrsets; i++)
+               new_rep->rrsets[i] = rep->rrsets[i];
+
+       return new_rep;
+}
+
 /** find the minimumttl in the rdata of SOA record */
 static time_t
 soa_find_minttl(struct rr_parse* rr)
@@ -196,13 +222,17 @@ rdata_copy(sldns_buffer* pkt, struct packed_rrset_data* data, uint8_t* to,
                 * minimum-ttl in the rdata of the SOA record */
                if(*rr_ttl > soa_find_minttl(rr))
                        *rr_ttl = soa_find_minttl(rr);
-               if(*rr_ttl > MAX_NEG_TTL)
-                       *rr_ttl = MAX_NEG_TTL;
        }
        if(!SERVE_ORIGINAL_TTL && (*rr_ttl < MIN_TTL))
                *rr_ttl = MIN_TTL;
        if(!SERVE_ORIGINAL_TTL && (*rr_ttl > MAX_TTL))
                *rr_ttl = MAX_TTL;
+       if(type == LDNS_RR_TYPE_SOA && section == LDNS_SECTION_AUTHORITY) {
+               /* max neg ttl overrides the min and max ttl of everything
+                * else, it is for a more specific record */
+               if(*rr_ttl > MAX_NEG_TTL)
+                       *rr_ttl = MAX_NEG_TTL;
+       }
        if(*rr_ttl < data->ttl)
                data->ttl = *rr_ttl;
 
@@ -488,14 +518,13 @@ int reply_info_parse(sldns_buffer* pkt, struct alloc_cache* alloc,
        if((ret = parse_packet(pkt, msg, region)) != 0) {
                return ret;
        }
-       if((ret = parse_extract_edns(msg, edns, region)) != 0)
+       if((ret = parse_extract_edns_from_response_msg(msg, edns, region)) != 0)
                return ret;
 
        /* parse OK, allocate return structures */
        /* this also performs dname decompression */
        if(!parse_create_msg(pkt, msg, alloc, qinf, rep, NULL)) {
                query_info_clear(qinf);
-               reply_info_parsedelete(*rep, alloc);
                *rep = NULL;
                return LDNS_RCODE_SERVFAIL;
        }
@@ -960,34 +989,6 @@ parse_reply_in_temp_region(sldns_buffer* pkt, struct regional* region,
        return rep;
 }
 
-int edns_opt_append(struct edns_data* edns, struct regional* region,
-       uint16_t code, size_t len, uint8_t* data)
-{
-       struct edns_option** prevp;
-       struct edns_option* opt;
-
-       /* allocate new element */
-       opt = (struct edns_option*)regional_alloc(region, sizeof(*opt));
-       if(!opt)
-               return 0;
-       opt->next = NULL;
-       opt->opt_code = code;
-       opt->opt_len = len;
-       opt->opt_data = NULL;
-       if(len > 0) {
-               opt->opt_data = regional_alloc_init(region, data, len);
-               if(!opt->opt_data)
-                       return 0;
-       }
-       
-       /* append at end of list */
-       prevp = &edns->opt_list;
-       while(*prevp != NULL)
-               prevp = &((*prevp)->next);
-       *prevp = opt;
-       return 1;
-}
-
 int edns_opt_list_append(struct edns_option** list, uint16_t code, size_t len,
        uint8_t* data, struct regional* region)
 {
@@ -1068,7 +1069,7 @@ static int inplace_cb_reply_call_generic(
                (void)(*(inplace_cb_reply_func_type*)cb->cb)(qinfo, qstate, rep,
                        rcode, edns, &opt_list_out, repinfo, region, start_time, cb->id, cb->cb_arg);
        }
-       edns->opt_list = opt_list_out;
+       edns->opt_list_inplace_cb_out = opt_list_out;
        return 1;
 }
 
index c6b220e..81c763f 100644 (file)
@@ -382,6 +382,21 @@ struct reply_info* reply_info_copy(struct reply_info* rep,
 int reply_info_alloc_rrset_keys(struct reply_info* rep,
        struct alloc_cache* alloc, struct regional* region);
 
+/*
+ * Create a new reply_info based on 'rep'.  The new info is based on
+ * the passed 'rep', but ignores any rrsets except for the first 'an_numrrsets'
+ * RRsets in the answer section.  These answer rrsets are copied to the
+ * new info, up to 'copy_rrsets' rrsets (which must not be larger than
+ * 'an_numrrsets').  If an_numrrsets > copy_rrsets, the remaining rrsets array
+ * entries will be kept empty so the caller can fill them later.  When rrsets
+ * are copied, they are shallow copied.  The caller must ensure that the
+ * copied rrsets are valid throughout its lifetime and must provide appropriate
+ * mutex if it can be shared by multiple threads.
+ */
+struct reply_info *
+make_new_reply_info(const struct reply_info* rep, struct regional* region,
+       size_t an_numrrsets, size_t copy_rrsets);
+
 /**
  * Copy a parsed rrset into given key, decompressing and allocating rdata.
  * @param pkt: packet for decompression
@@ -503,18 +518,6 @@ void log_reply_info(enum verbosity_value v, struct query_info *qinf,
 void log_query_info(enum verbosity_value v, const char* str, 
        struct query_info* qinf);
 
-/**
- * Append edns option to edns data structure
- * @param edns: the edns data structure to append the edns option to.
- * @param region: region to allocate the new edns option.
- * @param code: the edns option's code.
- * @param len: the edns option's length.
- * @param data: the edns option's data.
- * @return false on failure.
- */
-int edns_opt_append(struct edns_data* edns, struct regional* region,
-       uint16_t code, size_t len, uint8_t* data);
-
 /**
  * Append edns option to edns option list
  * @param list: the edns option list to append the edns option to.
index ff95c0a..e1feb22 100644 (file)
@@ -61,6 +61,13 @@ typedef uint64_t rrset_id_type;
  * updated on encoding in a reply.  This flag is not expected to be set in
  * cached data. */
 #define PACKED_RRSET_FIXEDTTL 0x80000000
+/** This rrset is from RPZ. It is not real, it is synthesized data to block
+ * access. The flag makes lookups, from cache in iterator, ignore the fake
+ * items and only use actual data.  Eg. when the iterator looksup NS, CNAME,
+ * A and AAAA types, it then gets items without this flag that are the
+ * actual network. But messages with these records in it can be stored in
+ * the cache and retrieved for a reply. */
+#define PACKED_RRSET_RPZ 0x8
 
 /** number of rrs and rrsets for integer overflow protection.  More than
  * this is not really possible (64K packet has much less RRs and RRsets) in
@@ -88,6 +95,7 @@ struct packed_rrset_key {
         *      o PACKED_RRSET_PARENT_SIDE
         *      o PACKED_RRSET_SOA_NEG
         *      o PACKED_RRSET_FIXEDTTL (not supposed to be cached)
+        *      o PACKED_RRSET_RPZ
         */
        uint32_t flags;
        /** the rrset type in network format */
index de6dbd0..05a22d4 100644 (file)
@@ -138,6 +138,7 @@ fptr_whitelist_comm_timer(void (*fptr)(void*))
        else if(fptr == &auth_xfer_probe_timer_callback) return 1;
        else if(fptr == &auth_xfer_transfer_timer_callback) return 1;
        else if(fptr == &mesh_serve_expired_callback) return 1;
+       else if(fptr == &serviced_timer_cb) return 1;
 #ifdef USE_DNSTAP
        else if(fptr == &mq_wakeup_cb) return 1;
 #endif
@@ -334,9 +335,10 @@ fptr_whitelist_hash_markdelfunc(lruhash_markdelfunc_type fptr)
 int 
 fptr_whitelist_modenv_send_query(struct outbound_entry* (*fptr)(
        struct query_info* qinfo, uint16_t flags, int dnssec, int want_dnssec,
-       int nocaps, struct sockaddr_storage* addr, socklen_t addrlen,
-       uint8_t* zone, size_t zonelen, int ssl_upstream, char* tls_auth_name,
-       struct module_qstate* q))
+       int nocaps, int check_ratelimit, struct sockaddr_storage* addr,
+       socklen_t addrlen, uint8_t* zone, size_t zonelen, int tcp_upstream,
+       int ssl_upstream, char* tls_auth_name, struct module_qstate* q,
+       int* was_ratelimited))
 {
        if(fptr == &worker_send_query) return 1;
        else if(fptr == &libworker_send_query) return 1;
index cd331fe..a0d9867 100644 (file)
@@ -211,9 +211,10 @@ int fptr_whitelist_hash_markdelfunc(lruhash_markdelfunc_type fptr);
  */
 int fptr_whitelist_modenv_send_query(struct outbound_entry* (*fptr)(
        struct query_info* qinfo, uint16_t flags, int dnssec, int want_dnssec,
-       int nocaps, struct sockaddr_storage* addr, socklen_t addrlen,
-       uint8_t* zone, size_t zonelen, int ssl_upstream, char* tls_auth_name,
-       struct module_qstate* q));
+       int nocaps, int check_ratelimit, struct sockaddr_storage* addr,
+       socklen_t addrlen, uint8_t* zone, size_t zonelen, int tcp_upstream,
+       int ssl_upstream, char* tls_auth_name, struct module_qstate* q,
+       int* was_ratelimited));
 
 /**
  * Check function pointer whitelist for module_env detach_subs callback values.
index b93af01..c7662dc 100644 (file)
 2870,
 2871,
 2872,
+2873,
 2874,
 2875,
 2876,
 4308,
 4309,
 4310,
+4319,
 4320,
 4321,
 4322,
 5026,
 5027,
 5029,
-5030,
 5031,
 5042,
 5043,
index 661d88d..c05dc66 100644 (file)
@@ -337,6 +337,15 @@ int event_del(struct event* ev)
                FD_CLR(FD_SET_T ev->ev_fd, &ev->ev_base->writes);
                FD_CLR(FD_SET_T ev->ev_fd, &ev->ev_base->ready);
                FD_CLR(FD_SET_T ev->ev_fd, &ev->ev_base->content);
+               if(ev->ev_fd == ev->ev_base->maxfd) {
+                        int i = ev->ev_base->maxfd - 1;
+                        for (; i > 3; i--) {
+                                if (NULL != ev->ev_base->fds[i]) {
+                                        break;
+                                }
+                        }
+                        ev->ev_base->maxfd = i;
+                }
        }
        ev->added = 0;
        return 0;
index 81a31a9..7a54800 100644 (file)
@@ -350,14 +350,18 @@ struct module_env {
         *      EDNS, the answer is likely to be useless for this domain.
         * @param nocaps: do not use caps_for_id, use the qname as given.
         *      (ignored if caps_for_id is disabled).
+        * @param check_ratelimit: if set, will check ratelimit before sending out.
         * @param addr: where to.
         * @param addrlen: length of addr.
         * @param zone: delegation point name.
         * @param zonelen: length of zone name.
+        * @param tcp_upstream: use TCP for upstream queries.
         * @param ssl_upstream: use SSL for upstream queries.
         * @param tls_auth_name: if ssl_upstream, use this name with TLS
         *      authentication.
-        * @param q: wich query state to reactivate upon return.
+        * @param q: which query state to reactivate upon return.
+        * @param was_ratelimited: it will signal back if the query failed to pass the
+        *      ratelimit check.
         * @return: false on failure (memory or socket related). no query was
         *      sent. Or returns an outbound entry with qsent and qstate set.
         *      This outbound_entry will be used on later module invocations
@@ -365,9 +369,10 @@ struct module_env {
         */
        struct outbound_entry* (*send_query)(struct query_info* qinfo,
                uint16_t flags, int dnssec, int want_dnssec, int nocaps,
+               int check_ratelimit,
                struct sockaddr_storage* addr, socklen_t addrlen,
-               uint8_t* zone, size_t zonelen, int ssl_upstream,
-               char* tls_auth_name, struct module_qstate* q);
+               uint8_t* zone, size_t zonelen, int tcp_upstream, int ssl_upstream,
+               char* tls_auth_name, struct module_qstate* q, int* was_ratelimited);
 
        /**
         * Detach-subqueries.
index f8b6090..8bef568 100644 (file)
@@ -44,6 +44,9 @@
 #ifdef HAVE_NET_IF_H
 #include <net/if.h>
 #endif
+#ifdef HAVE_NETIOAPI_H
+#include <netioapi.h>
+#endif
 #include "util/net_help.h"
 #include "util/log.h"
 #include "util/data/dname.h"
@@ -52,6 +55,7 @@
 #include "util/config_file.h"
 #include "sldns/parseutil.h"
 #include "sldns/wire2str.h"
+#include "sldns/str2wire.h"
 #include <fcntl.h>
 #ifdef HAVE_OPENSSL_SSL_H
 #include <openssl/ssl.h>
@@ -476,6 +480,42 @@ int authextstrtoaddr(char* str, struct sockaddr_storage* addr,
        return ipstrtoaddr(str, port, addr, addrlen);
 }
 
+uint8_t* authextstrtodname(char* str, int* port, char** auth_name)
+{
+       char* s;
+       uint8_t* dname;
+       size_t dname_len;
+       *port = UNBOUND_DNS_PORT;
+       *auth_name = NULL;
+       if((s=strchr(str, '@'))) {
+               char* hash = strchr(s+1, '#');
+               if(hash) {
+                       *auth_name = hash+1;
+               } else {
+                       *auth_name = NULL;
+               }
+               *port = atoi(s+1);
+               if(*port == 0) {
+                       if(!hash && strcmp(s+1,"0")!=0)
+                               return 0;
+                       if(hash && strncmp(s+1,"0#",2)!=0)
+                               return 0;
+               }
+               *s = 0;
+               dname = sldns_str2wire_dname(str, &dname_len);
+               *s = '@';
+       } else if((s=strchr(str, '#'))) {
+               *port = UNBOUND_DNS_OVER_TLS_PORT;
+               *auth_name = s+1;
+               *s = 0;
+               dname = sldns_str2wire_dname(str, &dname_len);
+               *s = '#';
+       } else {
+               dname = sldns_str2wire_dname(str, &dname_len);
+       }
+       return dname;
+}
+
 /** store port number into sockaddr structure */
 void
 sockaddr_store_port(struct sockaddr_storage* addr, socklen_t addrlen, int port)
@@ -890,6 +930,12 @@ log_cert(unsigned level, const char* str, void* cert)
        BIO_write(bio, &nul, (int)sizeof(nul));
        len = BIO_get_mem_data(bio, &pp);
        if(len != 0 && pp) {
+               /* reduce size of cert printout */
+               char* s;
+               while((s=strstr(pp, "  "))!=NULL)
+                       memmove(s, s+1, strlen(s+1)+1);
+               while((s=strstr(pp, "\t\t"))!=NULL)
+                       memmove(s, s+1, strlen(s+1)+1);
                verbose(level, "%s: \n%s", str, pp);
        }
        BIO_free(bio);
@@ -954,9 +1000,12 @@ listen_sslctx_setup(void* ctxt)
        }
 #endif
 #if defined(SHA256_DIGEST_LENGTH) && defined(USE_ECDSA)
+       /* if we detect system-wide crypto policies, use those */
+       if (access( "/etc/crypto-policies/config", F_OK ) != 0 ) {
        /* if we have sha256, set the cipher list to have no known vulns */
-       if(!SSL_CTX_set_cipher_list(ctx, "TLS13-CHACHA20-POLY1305-SHA256:TLS13-AES-256-GCM-SHA384:TLS13-AES-128-GCM-SHA256:ECDHE-ECDSA-CHACHA20-POLY1305:ECDHE-RSA-CHACHA20-POLY1305:ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256"))
-               log_crypto_err("could not set cipher list with SSL_CTX_set_cipher_list");
+               if(!SSL_CTX_set_cipher_list(ctx, "TLS13-CHACHA20-POLY1305-SHA256:TLS13-AES-256-GCM-SHA384:TLS13-AES-128-GCM-SHA256:ECDHE-ECDSA-CHACHA20-POLY1305:ECDHE-RSA-CHACHA20-POLY1305:ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256"))
+                       log_crypto_err("could not set cipher list with SSL_CTX_set_cipher_list");
+       }
 #endif
 
        if((SSL_CTX_set_options(ctx, SSL_OP_CIPHER_SERVER_PREFERENCE) &
@@ -1181,6 +1230,7 @@ void* connect_sslctx_create(char* key, char* pem, char* verifypem, int wincert)
        if((SSL_CTX_set_options(ctx, SSL_OP_NO_RENEGOTIATION) &
                SSL_OP_NO_RENEGOTIATION) != SSL_OP_NO_RENEGOTIATION) {
                log_crypto_err("could not set SSL_OP_NO_RENEGOTIATION");
+               SSL_CTX_free(ctx);
                return 0;
        }
 #endif
index 7983527..4dd3984 100644 (file)
@@ -210,17 +210,30 @@ int netblockstrtoaddr(const char* ip, int port, struct sockaddr_storage* addr,
 /**
  * Convert address string, with "@port" appendix, to sockaddr.
  * It can also have an "#tls-auth-name" appendix (after the port).
- * The returned tls-auth-name string is a pointer into the input string.
- * Uses DNS port by default.
+ * The returned auth_name string is a pointer into the input string.
+ * Uses DNS port by default; TLS port when a "#tls-auth-name" is configured.
  * @param str: the string
  * @param addr: where to store sockaddr.
  * @param addrlen: length of stored sockaddr is returned.
  * @param auth_name: returned pointer to tls_auth_name, or NULL if none.
  * @return 0 on error.
  */
-int authextstrtoaddr(char* str, struct sockaddr_storage* addr, 
+int authextstrtoaddr(char* str, struct sockaddr_storage* addr,
        socklen_t* addrlen, char** auth_name);
 
+/**
+ * Convert domain string, with "@port" appendix, to dname.
+ * It can also have an "#tls-auth-name" appendix (after the port).
+ * The return port is the parsed port.
+ * Uses DNS port by default; TLS port when a "#tls-auth-name" is configured.
+ * The returned auth_name string is a pointer into the input string.
+ * @param str: the string
+ * @param port: pointer to be assigned the parsed port value.
+ * @param auth_name: returned pointer to tls_auth_name, or NULL if none.
+ * @return pointer to the dname.
+ */
+uint8_t* authextstrtodname(char* str, int* port, char** auth_name);
+
 /**
  * Store port number into sockaddr structure
  * @param addr: sockaddr structure, ip4 or ip6.
index 11c642a..b9b7230 100644 (file)
@@ -300,6 +300,7 @@ udp_send_errno_needs_log(struct sockaddr* addr, socklen_t addrlen)
                case ENETDOWN:
 #  endif
                case EPERM:
+               case EACCES:
                        if(verbosity < VERB_ALGO)
                                return 0;
                default:
@@ -817,6 +818,7 @@ setup_tcp_handler(struct comm_point* c, int fd, int cur, int max)
 #endif
        c->tcp_is_reading = 1;
        c->tcp_byte_count = 0;
+       c->tcp_keepalive = 0;
        /* if more than half the tcp handlers are in use, use a shorter
         * timeout for this TCP connection, we need to make space for
         * other connections to be able to get attention */
@@ -942,7 +944,16 @@ int comm_point_perform_accept(struct comm_point* c,
 
 #ifdef USE_WINSOCK
 static long win_bio_cb(BIO *b, int oper, const char* ATTR_UNUSED(argp),
-        int ATTR_UNUSED(argi), long argl, long retvalue)
+#ifdef HAVE_BIO_SET_CALLBACK_EX
+       size_t ATTR_UNUSED(len),
+#endif
+        int ATTR_UNUSED(argi), long argl,
+#ifndef HAVE_BIO_SET_CALLBACK_EX
+       long retvalue
+#else
+       int retvalue, size_t* ATTR_UNUSED(processed)
+#endif
+       )
 {
        int wsa_err = WSAGetLastError(); /* store errcode before it is gone */
        verbose(VERB_ALGO, "bio_cb %d, %s %s %s", oper,
@@ -972,9 +983,17 @@ comm_point_tcp_win_bio_cb(struct comm_point* c, void* thessl)
 {
        SSL* ssl = (SSL*)thessl;
        /* set them both just in case, but usually they are the same BIO */
+#ifdef HAVE_BIO_SET_CALLBACK_EX
+       BIO_set_callback_ex(SSL_get_rbio(ssl), &win_bio_cb);
+#else
        BIO_set_callback(SSL_get_rbio(ssl), &win_bio_cb);
+#endif
        BIO_set_callback_arg(SSL_get_rbio(ssl), (char*)c->ev->ev);
+#ifdef HAVE_BIO_SET_CALLBACK_EX
+       BIO_set_callback_ex(SSL_get_wbio(ssl), &win_bio_cb);
+#else
        BIO_set_callback(SSL_get_wbio(ssl), &win_bio_cb);
+#endif
        BIO_set_callback_arg(SSL_get_wbio(ssl), (char*)c->ev->ev);
 }
 #endif
@@ -1036,6 +1055,7 @@ comm_point_tcp_accept_callback(int fd, short event, void* arg)
        /* clear leftover flags from previous use, and then set the
         * correct event base for the event structure for libevent */
        ub_event_free(c_hdl->ev->ev);
+       c_hdl->ev->ev = NULL;
        if((c_hdl->type == comm_tcp && c_hdl->tcp_req_info) ||
                c_hdl->type == comm_local || c_hdl->type == comm_raw)
                c_hdl->tcp_do_toggle_rw = 0;
@@ -1092,6 +1112,7 @@ comm_point_tcp_accept_callback(int fd, short event, void* arg)
        /* grab the tcp handler buffers */
        c->cur_tcp_count++;
        c->tcp_free = c_hdl->tcp_free;
+       c_hdl->tcp_free = NULL;
        if(!c->tcp_free) {
                /* stop accepting incoming queries for now. */
                comm_point_stop_listening(c);
@@ -1113,9 +1134,11 @@ reclaim_tcp_handler(struct comm_point* c)
        }
        comm_point_close(c);
        if(c->tcp_parent) {
-               c->tcp_parent->cur_tcp_count--;
-               c->tcp_free = c->tcp_parent->tcp_free;
-               c->tcp_parent->tcp_free = c;
+               if(c != c->tcp_parent->tcp_free) {
+                       c->tcp_parent->cur_tcp_count--;
+                       c->tcp_free = c->tcp_parent->tcp_free;
+                       c->tcp_parent->tcp_free = c;
+               }
                if(!c->tcp_free) {
                        /* re-enable listening on accept socket */
                        comm_point_start_listening(c->tcp_parent, -1, -1);
@@ -1123,6 +1146,8 @@ reclaim_tcp_handler(struct comm_point* c)
        }
        c->tcp_more_read_again = NULL;
        c->tcp_more_write_again = NULL;
+       c->tcp_byte_count = 0;
+       sldns_buffer_clear(c->buffer);
 }
 
 /** do the callback when writing is done */
@@ -1862,13 +1887,22 @@ comm_point_tcp_handle_write(int fd, struct comm_point* c)
                        if(errno == EINTR || errno == EAGAIN)
                                return 1;
                        /* Not handling EISCONN here as shouldn't ever hit that case.*/
-                       if(errno != EPIPE && errno != 0 && verbosity < 2)
-                               return 0; /* silence lots of chatter in the logs */
-                       if(errno != EPIPE && errno != 0) {
+                       if(errno != EPIPE
+#ifdef EOPNOTSUPP
+                               /* if /proc/sys/net/ipv4/tcp_fastopen is
+                                * disabled on Linux, sendmsg may return
+                                * 'Operation not supported', if so
+                                * fallthrough to ordinary connect. */
+                               && errno != EOPNOTSUPP
+#endif
+                               && errno != 0) {
+                               if(verbosity < 2)
+                                       return 0; /* silence lots of chatter in the logs */
                                log_err_addr("tcp sendmsg", strerror(errno),
                                        &c->repinfo.addr, c->repinfo.addrlen);
                                return 0;
                        }
+                       verbose(VERB_ALGO, "tcp sendmsg for fastopen failed (with %s), try normal connect", strerror(errno));
                        /* fallthrough to nonFASTOPEN
                         * (MSG_FASTOPEN on Linux 3 produces EPIPE)
                         * we need to perform connect() */
@@ -2201,9 +2235,11 @@ reclaim_http_handler(struct comm_point* c)
        }
        comm_point_close(c);
        if(c->tcp_parent) {
-               c->tcp_parent->cur_tcp_count--;
-               c->tcp_free = c->tcp_parent->tcp_free;
-               c->tcp_parent->tcp_free = c;
+               if(c != c->tcp_parent->tcp_free) {
+                       c->tcp_parent->cur_tcp_count--;
+                       c->tcp_free = c->tcp_parent->tcp_free;
+                       c->tcp_parent->tcp_free = c;
+               }
                if(!c->tcp_free) {
                        /* re-enable listening on accept socket */
                        comm_point_start_listening(c->tcp_parent, -1, -1);
@@ -4140,6 +4176,10 @@ comm_point_start_listening(struct comm_point* c, int newfd, int msec)
                c->timeout->tv_sec = msec/1000;
                c->timeout->tv_usec = (msec%1000)*1000;
 #endif /* S_SPLINT_S */
+       } else {
+               if(msec == 0 || !c->timeout) {
+                       ub_event_del_bits(c->ev->ev, UB_EV_TIMEOUT);
+               }
        }
        if(c->type == comm_tcp || c->type == comm_http) {
                ub_event_del_bits(c->ev->ev, UB_EV_READ|UB_EV_WRITE);
@@ -4164,6 +4204,7 @@ comm_point_start_listening(struct comm_point* c, int newfd, int msec)
        }
        if(ub_event_add(c->ev->ev, msec==0?NULL:c->timeout) != 0) {
                log_err("event_add failed. in cpsl.");
+               return;
        }
        c->event_added = 1;
 }
@@ -4177,11 +4218,15 @@ void comm_point_listen_for_rw(struct comm_point* c, int rd, int wr)
                }
                c->event_added = 0;
        }
+       if(!c->timeout) {
+               ub_event_del_bits(c->ev->ev, UB_EV_TIMEOUT);
+       }
        ub_event_del_bits(c->ev->ev, UB_EV_READ|UB_EV_WRITE);
        if(rd) ub_event_add_bits(c->ev->ev, UB_EV_READ);
        if(wr) ub_event_add_bits(c->ev->ev, UB_EV_WRITE);
        if(ub_event_add(c->ev->ev, c->timeout) != 0) {
                log_err("event_add failed. in cplf.");
+               return;
        }
        c->event_added = 1;
 }
index c79f99b..9f4d28b 100644 (file)
@@ -743,7 +743,7 @@ struct comm_signal* comm_signal_create(struct comm_base* base,
        void (*callback)(int, void*), void* cb_arg);
 
 /**
- * Bind signal struct to catch a signal. A signle comm_signal can be bound
+ * Bind signal struct to catch a signal. A single comm_signal can be bound
  * to multiple signals, calling comm_signal_bind multiple times.
  * @param comsig: the communication point, with callback information.
  * @param sig: signal number.
index 51039ab..6fd1f5e 100644 (file)
@@ -281,7 +281,7 @@ void shm_main_run(struct worker *worker)
                shm_stat->mem.subnet = 0;
 #ifdef CLIENT_SUBNET
                shm_stat->mem.subnet = (long long)mod_get_mem(&worker->env,
-                       "subnet");
+                       "subnetcache");
 #endif
                /* ipsecmod mem value is available in shm, also when not enabled,
                 * to make the struct easier to memmap by other applications,
index dc6e3c2..40556e7 100644 (file)
@@ -363,7 +363,11 @@ int tube_read_msg(struct tube* tube, uint8_t** buf, uint32_t* len,
                }
                d += r;
        }
-       log_assert(*len < 65536*2);
+       if (*len >= 65536*2) {
+               log_err("tube msg length %u is too big", (unsigned)*len);
+               (void)fd_set_nonblock(fd);
+               return 0;
+       }
        *buf = (uint8_t*)malloc(*len);
        if(!*buf) {
                log_err("tube read out of memory");
index 68f633b..8cd87ec 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * util/ub_event.c - directly call libevent (compatability) functions
+ * util/ub_event.c - directly call libevent (compatibility) functions
  *
  * Copyright (c) 2007, NLnet Labs. All rights reserved.
  *
index 9643a3d..55e82c1 100644 (file)
@@ -2377,7 +2377,9 @@ probe_anchor(struct module_env* env, struct trust_anchor* tp)
        edns.ext_rcode = 0;
        edns.edns_version = 0;
        edns.bits = EDNS_DO;
-       edns.opt_list = NULL;
+       edns.opt_list_in = NULL;
+       edns.opt_list_out = NULL;
+       edns.opt_list_inplace_cb_out = NULL;
        edns.padding_block_size = 0;
        if(sldns_buffer_capacity(buf) < 65535)
                edns.udp_size = (uint16_t)sldns_buffer_capacity(buf);
index dd8d320..bb366d3 100644 (file)
@@ -767,15 +767,15 @@ val_dsset_isusable(struct ub_packed_rrset_key* ds_rrset)
                sldns_lookup_table *lt;
                char herr[64], aerr[64];
                lt = sldns_lookup_by_id(sldns_hashes,
-                       (int)ds_get_digest_algo(ds_rrset, i));
+                       (int)ds_get_digest_algo(ds_rrset, 0));
                if(lt) snprintf(herr, sizeof(herr), "%s", lt->name);
                else snprintf(herr, sizeof(herr), "%d",
-                       (int)ds_get_digest_algo(ds_rrset, i));
+                       (int)ds_get_digest_algo(ds_rrset, 0));
                lt = sldns_lookup_by_id(sldns_algorithms,
-                       (int)ds_get_key_algo(ds_rrset, i));
+                       (int)ds_get_key_algo(ds_rrset, 0));
                if(lt) snprintf(aerr, sizeof(aerr), "%s", lt->name);
                else snprintf(aerr, sizeof(aerr), "%d",
-                       (int)ds_get_key_algo(ds_rrset, i));
+                       (int)ds_get_key_algo(ds_rrset, 0));
                verbose(VERB_ALGO, "DS unsupported, hash %s %s, "
                        "key algorithm %s %s", herr,
                        (ds_digest_algo_is_supported(ds_rrset, 0)?
index d4d48d9..e630728 100644 (file)
@@ -140,7 +140,7 @@ val_apply_cfg(struct module_env* env, struct val_env* val_env,
        val_env->max_restart = cfg->val_max_restart;
        c = cfg_count_numbers(cfg->val_nsec3_key_iterations);
        if(c < 1 || (c&1)) {
-               log_err("validator: unparseable or odd nsec3 key "
+               log_err("validator: unparsable or odd nsec3 key "
                        "iterations: %s", cfg->val_nsec3_key_iterations);
                return 0;
        }
@@ -484,7 +484,7 @@ generate_keytag_query(struct module_qstate* qstate, int id,
                return 0;
        }
 
-       /* Not interrested in subquery response. Restore the ext_state,
+       /* Not interested in subquery response. Restore the ext_state,
         * that might be changed by generate_request() */
        qstate->ext_state[id] = ext_state;
 
index a928e10..a97eab2 100644 (file)
@@ -68,7 +68,7 @@ struct config_strlist;
 #define SENTINEL_IS            "root-key-sentinel-is-ta-"
 /** Root key sentinel is not ta preamble */
 #define SENTINEL_NOT           "root-key-sentinel-not-ta-"
-/** Root key sentinal keytag length */
+/** Root key sentinel keytag length */
 #define SENTINEL_KEYTAG_LEN    5
 
 /**