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@
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
# 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
[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
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).
# 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
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
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
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"
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"
])
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"
])
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;
#! /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
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."
# 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
i*:PW*:*)
GUESS=$UNAME_MACHINE-pc-pw32
;;
+ *:SerenityOS:*:*)
+ GUESS=$UNAME_MACHINE-pc-serenity
+ ;;
*:Interix*:*)
case $UNAME_MACHINE in
x86)
i*86:rdos:*:*)
GUESS=$UNAME_MACHINE-pc-rdos
;;
+ i*86:Fiwix:*:*)
+ GUESS=$UNAME_MACHINE-pc-fiwix
+ ;;
*:AROS:*:*)
GUESS=$UNAME_MACHINE-unknown-aros
;;
/* 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
#! /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
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."
# 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
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]* \
*-*)
# 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
;;
# 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
xscale-* | xscalee[bl]-*)
cpu=`echo "$cpu" | sed 's/^xscale/arm/'`
;;
- arm64-*)
+ arm64-* | aarch64le-*)
cpu=aarch64
;;
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*)
;;
*-*)
# 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*)
# 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*)
| 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*)
# 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
#! /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>.
#
# 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=''
HAVE_SSL
PC_CRYPTO_DEPENDENCY
CONFIG_DATE
+GCC_DOCKER_LINTFLAGS
NETBSD_LINTFLAGS
PYUNBOUND_UNINSTALL
PYUNBOUND_INSTALL
SWIG_LIB
SWIG
PC_PY_DEPENDENCY
+PYTHON_LIBS
PY_MAJOR_VERSION
PYTHON_SITE_PKG
PYTHON_LDFLAGS
# 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]...
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
--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
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.
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
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
# 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
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.
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
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
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
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
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; }
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)
{ 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; }
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
;;
esac
-# check wether gost also works
+# check whether gost also works
# Check whether --enable-gost was given.
if test ${enable_gost+y}
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 :
# 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; }
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
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
-version=1.13.2
+version=1.15.0
date=`date +'%b %e, %Y'`
# 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
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\\"
# 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
# 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
# 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.
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)
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
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
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)
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)
])
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
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"
;;
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>
])
# 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
}
#endif /* USE_WINSOCK */
signal_handling_record();
- checklock_start();
#ifdef HAVE_SSL
# ifdef HAVE_ERR_LOAD_CRYPTO_STRINGS
ERR_load_crypto_strings();
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;
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);
*/
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)
(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
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");
/** 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;
}
/* 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;
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");
/* parse dp */
if(dp) {
- if(!(*dp = parse_delegpt(ssl, args, *nm, 1))) {
+ if(!(*dp = parse_delegpt(ssl, args, *nm))) {
free(*nm);
return 0;
}
int all;
/** current time */
time_t now;
+ /** if backoff is enabled */
+ int backoff;
};
#define ip_ratelimit_list_arg ratelimit_list_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;
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;
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;
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;
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;
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);
(&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 */
(&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 */
* 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;
}
}
/* 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;
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);
}
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;
}
} else *is_secure_answer = 0;
- edns_bak = *edns;
edns->edns_version = EDNS_ADVERTISED_VERSION;
edns->udp_size = EDNS_ADVERTISED_SIZE;
edns->ext_rcode = 0;
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);
}
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));
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);
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);
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);
/* 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,
}
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);
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);
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) {
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);
* 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));
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(
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;
}
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;
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;
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
/**
* 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
*/
/**
* 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.
/**
* 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.
*/
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.
+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.
-README for Unbound 1.13.2
+README for Unbound 1.15.0
Copyright 2007 NLnet Labs
http://unbound.net
#
# 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.
# 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
# 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
# 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
# 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 /.
# 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.
# 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).
# 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
# 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
# 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
# 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
# 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
# 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
# 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
# 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
#
# 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.
# 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:
# 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:
# 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:
# 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.
# 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
# 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"
# 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
# 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: ""
# 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"
# rpz-cname-override: www.example.org
# rpz-log: yes
# rpz-log-name: "example policy"
+# rpz-signal-nxdomain-ra: no
+# for-downstream: no
# tags: "example"
-.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
.\"
.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
-.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
.\"
.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.
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
.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).
-.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
.\"
.\"
.SH "NAME"
unbound\-checkconf
-\- Check unbound configuration file for errors.
+\- Check Unbound configuration file for errors.
.SH "SYNOPSIS"
.B unbound\-checkconf
.RB [ \-h ]
.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:
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).
-.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:
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
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
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
.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
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,
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,
.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
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
.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
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.
.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
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
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.
.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
.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).
-.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
.\"
.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:
.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
.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).
-.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
.\"
.\"
.SH "NAME"
.B unbound
-\- Unbound DNS validating resolver 1.13.2.
+\- Unbound DNS validating resolver 1.15.0.
.SH "SYNOPSIS"
.B unbound
.RB [ \-h ]
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
.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
-.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
.\"
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>
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
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:
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.
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.
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
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
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
.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
.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,
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>
.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.
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
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.
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>
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.
.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>
.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
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).
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>
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".
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".
.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.
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
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
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
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
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
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.
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
.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
.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
.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.
.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
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,
.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.
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
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
.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>
.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.
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
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>
.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
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
.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
.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
.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
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.
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
.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.
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
.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.
\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.
.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>
.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
.SH "FILES"
.TP
.I @UNBOUND_RUN_DIR@
-default unbound working directory.
+default Unbound working directory.
.TP
.I @UNBOUND_CHROOT_DIR@
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),
# 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
# 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.
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) {
* \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.
*/
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;
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;
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;
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;
}
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);
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)
(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;
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;
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;
while(n) {
nn = n->next;
free(n->name);
+ free(n->tls_auth_name);
free(n);
n = nn;
}
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;
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)
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)
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 */
* 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;
};
/**
* @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.
* @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.
* @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.
}
/** 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;
"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;
}
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))
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)) {
}
/** 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;
"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;
}
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;
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;
}
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:
* 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
* \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"
return 1;
}
-int
+int
iter_apply_cfg(struct iter_env* iter_env, struct config_file* cfg)
{
int i;
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)) {
}
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;
}
* 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.
* 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;
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,
/** 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)
{
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))
int rtt_band;
size_t i;
int* rtt_list, *rtt_index;
-
+
if(num_results < 1 || n >= num_results) {
return -1;
}
* 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;
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)) {
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)
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;
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) {
}
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)
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,
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,
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)
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;
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);
}
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;
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;
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,
}
}
-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;
/* 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;
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);
return 0;
}
-int
+int
iter_indicates_dnssec(struct module_env* env, struct delegpt* dp,
struct dns_msg* msg, uint16_t dclass)
{
return 0;
}
-int
+int
iter_msg_has_dnssec(struct dns_msg* msg)
{
size_t i;
* 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 &&
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) ||
}
/**
- * check equality of two rrsets
+ * check equality of two rrsets
* @param k1: rrset
* @param k2: rrset
* @return true if equal
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;
}
return 0;
}
-int
+int
reply_equal(struct reply_info* p, struct reply_info* q, struct regional* region)
{
size_t i;
return 1;
}
-void
+void
caps_strip_reply(struct reply_info* rep)
{
size_t i;
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;
}
}
-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;
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");
}
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) {
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);
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);
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);
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;
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. */
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--;
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;
}
}
-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) {
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 */
* 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
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:
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;
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);
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
(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;
/* 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,
(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;
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);
}
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);
*
* @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
*/
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))
* 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 ||
}
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++;
/* 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;
/* 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");
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 */
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);
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;
}
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");
/**
* 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 */
* 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. */
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;
};
/**
/** 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. */
#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"
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)
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.
*
#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>
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);
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);
}
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);
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(
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(
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;
}
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;
*
* 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
* 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
*/
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
/**
* 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);
* @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,
* @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
#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 */
* 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));
*/
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;
&ss, addrlen);
if(ra) {
*rrset_id = i;
+ *rr_id = j;
lock_rw_rdlock(&ra->lock);
lock_rw_unlock(&rs->lock);
return ra;
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.
"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;
}
* 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;
* 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(). */
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;
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;
}
}
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,
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)) {
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;
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;
}
*/
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 */
#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
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)
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)
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);
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);
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);
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);
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");
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;
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;
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) {
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;
}
}
/* 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;
}
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) {
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;
}
* @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;
} 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;
}
} 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;
}
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;
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;
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 &&
* 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);
}
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;
}
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;
/* 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);
* 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 */
}
auth_zone_verify_zonemd_with_key(z, env, mods, dnskey, is_insecure,
- result);
+ result, NULL);
regional_free_all(env->scratch);
}
* 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 */
/** 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);
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;
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++) {
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;
/* 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);
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,
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;
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);
}
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;
/* 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) {
* @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
* 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);
/**
* @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,
* @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);
/**
* 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).
* @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).
*/
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);
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,
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 "
}
} 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
#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
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))) {
* 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,
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) {
/* 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;
}
*/
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.
* 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)
{
/* 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
}
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");
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;
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,
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);
}
/* 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);
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,
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,
*/
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,
* 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,
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";
*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;
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
};
* @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.
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 */
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;
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);
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);
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);
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;
}
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;
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,
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.
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 &&
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);
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);
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),
{
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;
}
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
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;
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;
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;
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)
{
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;
}
}
+/** 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
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);
}
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) {
}
}
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));
{
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;
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 */
NETEVENT_CLOSED, NULL);
}
pending_delete(outnet, pend);
+ } else {
+ pend->sq->busy = 0;
}
}
}
(*num_ip4)++;
}
}
-
}
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);
}
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;
}
case ENETDOWN:
# endif
case EPERM:
+ case EACCES:
if(verbosity >= VERB_ALGO)
return 1;
return 0;
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;
}
}
/* 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);
#ifdef USE_DNSTAP
w->sq = NULL;
#endif
+ w->in_cb_and_decommission = 0;
if(pend) {
/* we have a buffer available right now */
if(reuse) {
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;
}
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;
}
}
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;
sq->to_be_deleted = 0;
sq->padding_block_size = pad_queries_block_size;
#ifdef UNBOUND_DEBUG
- ins =
+ ins =
#else
(void)
#endif
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);
}
}
}
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)
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);
* 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;
}
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");
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;
}
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 */
} 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;
}
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 */
/*
* 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
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 */
if((*pp)->cb_arg == cb_arg) {
struct service_callback* del = *pp;
*pp = del->next;
- free(del);
return;
}
pp = &(*pp)->next;
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);
}
}
#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;
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;
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;
};
/**
* @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
* @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.
/** 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);
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;
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;
* 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)
#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));
{
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);
}
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;
}
/* 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.
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];
#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
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 */
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++);
}
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.
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);
}
#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"
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)) {
&& 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
&& 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
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")))
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);
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")))
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;
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;
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;
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;
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)
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)
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)
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)
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;
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.
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 */
/** 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 */
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.
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) }
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) }
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) }
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) }
* 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
%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
%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
%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
%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 |
;
/* server: declaration */
serverstart: VAR_SERVER
- {
+ {
OUTYY(("\nP(server:)\n"));
}
;
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 |
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 |
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 |
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
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;
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 |
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
{
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)
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)
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");
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");
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);
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);
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
}
;
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));
}
;
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));
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));
}
}
;
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));
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");
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);
}
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);
}
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");
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");
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);
}
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);
}
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);
}
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);
}
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);
}
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);
}
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);
}
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);
}
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);
}
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 "
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");
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);
}
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);
}
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");
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");
}
}
}
;
-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);
}
;
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));
}
;
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");
}
}
;
-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);
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);
}
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);
}
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);
}
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));
#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");
}
}
;
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 |
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);
}
}
;
pythonstart: VAR_PYTHON
- {
- OUTYY(("\nP(python:)\n"));
+ {
+ OUTYY(("\nP(python:)\n"));
}
;
contents_py: contents_py content_py
;
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
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 */
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;
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);
}
* 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"
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) {
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;
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 */
}
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;
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 */
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
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
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;
};
* @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.
* 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.
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)
* 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;
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;
}
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)
{
(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;
}
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
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.
* 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
* 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 */
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
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;
*/
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.
2870,
2871,
2872,
+2873,
2874,
2875,
2876,
4308,
4309,
4310,
+4319,
4320,
4321,
4322,
5026,
5027,
5029,
-5030,
5031,
5042,
5043,
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;
* 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
*/
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.
#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"
#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>
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)
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);
}
#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) &
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
/**
* 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.
case ENETDOWN:
# endif
case EPERM:
+ case EACCES:
if(verbosity < VERB_ALGO)
return 0;
default:
#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 */
#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,
{
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
/* 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;
/* 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);
}
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);
}
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 */
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() */
}
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);
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);
}
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;
}
}
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;
}
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.
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,
}
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");
/*
- * 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.
*
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);
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)?
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;
}
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;
#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
/**