aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorCy Schubert <cy@FreeBSD.org>2020-12-16 09:21:40 +0000
committerCy Schubert <cy@FreeBSD.org>2020-12-16 09:21:40 +0000
commitbc4204071c57773d5a898901a33c2dc17a59fd47 (patch)
tree727e03c6178034cc6a5d430d574d3e51f446eba3
parent85effcfe0dae1342c7abd042eaa7f88aaaf65db2 (diff)
downloadsrc-bc4204071c57773d5a898901a33c2dc17a59fd47.tar.gz
src-bc4204071c57773d5a898901a33c2dc17a59fd47.zip
MFC r368478:
MFV r368464: Update unbound from 1.12.0 to 1.13.0 Security: CVE-2020-28935
Notes
Notes: svn path=/stable/12/; revision=368693
-rwxr-xr-xcontrib/unbound/config.guess215
-rwxr-xr-xcontrib/unbound/config.sub49
-rwxr-xr-xcontrib/unbound/configure55
-rw-r--r--contrib/unbound/configure.ac23
-rw-r--r--contrib/unbound/contrib/README2
-rw-r--r--contrib/unbound/contrib/metrics.awk180
-rw-r--r--contrib/unbound/contrib/unbound.service.in2
-rw-r--r--contrib/unbound/contrib/unbound_portable.service.in2
-rw-r--r--contrib/unbound/daemon/daemon.c10
-rw-r--r--contrib/unbound/daemon/unbound.c55
-rw-r--r--contrib/unbound/daemon/worker.c8
-rw-r--r--contrib/unbound/dnstap/dnstap.c10
-rw-r--r--contrib/unbound/dnstap/dtstream.c8
-rw-r--r--contrib/unbound/doc/Changelog163
-rw-r--r--contrib/unbound/doc/README2
-rw-r--r--contrib/unbound/doc/example.conf.in11
-rw-r--r--contrib/unbound/doc/libunbound.3.in4
-rw-r--r--contrib/unbound/doc/unbound-anchor.8.in2
-rw-r--r--contrib/unbound/doc/unbound-checkconf.8.in2
-rw-r--r--contrib/unbound/doc/unbound-control.8.in2
-rw-r--r--contrib/unbound/doc/unbound-host.1.in2
-rw-r--r--contrib/unbound/doc/unbound.8.in4
-rw-r--r--contrib/unbound/doc/unbound.conf.5.in35
-rw-r--r--contrib/unbound/libunbound/context.c2
-rw-r--r--contrib/unbound/libunbound/libunbound.c10
-rw-r--r--contrib/unbound/libunbound/libworker.c2
-rw-r--r--contrib/unbound/respip/respip.c6
-rw-r--r--contrib/unbound/services/authzone.c2
-rw-r--r--contrib/unbound/services/cache/infra.c28
-rw-r--r--contrib/unbound/services/cache/infra.h2
-rw-r--r--contrib/unbound/services/listen_dnsport.c54
-rw-r--r--contrib/unbound/services/listen_dnsport.h6
-rw-r--r--contrib/unbound/services/localzone.c2
-rw-r--r--contrib/unbound/services/mesh.c59
-rw-r--r--contrib/unbound/services/outside_network.c1089
-rw-r--r--contrib/unbound/services/outside_network.h145
-rw-r--r--contrib/unbound/services/rpz.c2
-rwxr-xr-xcontrib/unbound/smallapp/unbound-control-setup.sh.in13
-rw-r--r--contrib/unbound/util/config_file.c26
-rw-r--r--contrib/unbound/util/config_file.h14
-rw-r--r--contrib/unbound/util/configlexer.lex7
-rw-r--r--contrib/unbound/util/configparser.y68
-rw-r--r--contrib/unbound/util/data/msgencode.c3
-rw-r--r--contrib/unbound/util/data/msgreply.h2
-rw-r--r--contrib/unbound/util/edns.c73
-rw-r--r--contrib/unbound/util/edns.h52
-rw-r--r--contrib/unbound/util/fptr_wlist.c2
-rw-r--r--contrib/unbound/util/iana_ports.inc1
-rw-r--r--contrib/unbound/util/module.h4
-rw-r--r--contrib/unbound/util/netevent.c531
-rw-r--r--contrib/unbound/util/netevent.h44
-rw-r--r--contrib/unbound/util/regional.c31
-rw-r--r--contrib/unbound/util/regional.h13
-rw-r--r--contrib/unbound/validator/val_secalgo.c2
54 files changed, 2532 insertions, 609 deletions
diff --git a/contrib/unbound/config.guess b/contrib/unbound/config.guess
index 8d70ec2b2633..699b3a10b21c 100755
--- a/contrib/unbound/config.guess
+++ b/contrib/unbound/config.guess
@@ -2,7 +2,7 @@
# Attempt to guess a canonical system name.
# Copyright 1992-2020 Free Software Foundation, Inc.
-timestamp='2020-09-19'
+timestamp='2020-11-19'
# 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
@@ -27,12 +27,12 @@ timestamp='2020-09-19'
# Originally written by Per Bothner; maintained since 2000 by Ben Elliston.
#
# You can get the latest version of this script from:
-# https://git.savannah.gnu.org/gitweb/?p=config.git;a=blob_plain;f=config.guess
+# https://git.savannah.gnu.org/cgit/config.git/plain/config.guess
#
# Please send patches to <config-patches@gnu.org>.
-me=`echo "$0" | sed -e 's,.*/,,'`
+me=$(echo "$0" | sed -e 's,.*/,,')
usage="\
Usage: $0 [OPTION]
@@ -103,7 +103,7 @@ set_cc_for_build() {
test "$tmp" && return 0
: "${TMPDIR=/tmp}"
# shellcheck disable=SC2039
- { tmp=`(umask 077 && mktemp -d "$TMPDIR/cgXXXXXX") 2>/dev/null` && test -n "$tmp" && test -d "$tmp" ; } ||
+ { tmp=$( (umask 077 && mktemp -d "$TMPDIR/cgXXXXXX") 2>/dev/null) && test -n "$tmp" && test -d "$tmp" ; } ||
{ test -n "$RANDOM" && tmp=$TMPDIR/cg$$-$RANDOM && (umask 077 && mkdir "$tmp" 2>/dev/null) ; } ||
{ tmp=$TMPDIR/cg-$$ && (umask 077 && mkdir "$tmp" 2>/dev/null) && echo "Warning: creating insecure temp directory" >&2 ; } ||
{ echo "$me: cannot create a temporary directory in $TMPDIR" >&2 ; exit 1 ; }
@@ -131,16 +131,14 @@ if test -f /.attbin/uname ; then
PATH=$PATH:/.attbin ; export PATH
fi
-UNAME_MACHINE=`(uname -m) 2>/dev/null` || UNAME_MACHINE=unknown
-UNAME_RELEASE=`(uname -r) 2>/dev/null` || UNAME_RELEASE=unknown
-UNAME_SYSTEM=`(uname -s) 2>/dev/null` || UNAME_SYSTEM=unknown
-UNAME_VERSION=`(uname -v) 2>/dev/null` || UNAME_VERSION=unknown
+UNAME_MACHINE=$( (uname -m) 2>/dev/null) || UNAME_MACHINE=unknown
+UNAME_RELEASE=$( (uname -r) 2>/dev/null) || UNAME_RELEASE=unknown
+UNAME_SYSTEM=$( (uname -s) 2>/dev/null) || UNAME_SYSTEM=unknown
+UNAME_VERSION=$( (uname -v) 2>/dev/null) || UNAME_VERSION=unknown
case "$UNAME_SYSTEM" in
Linux|GNU|GNU/*)
- # If the system lacks a compiler, then just pick glibc.
- # We could probably try harder.
- LIBC=gnu
+ LIBC=unknown
set_cc_for_build
cat <<-EOF > "$dummy.c"
@@ -149,16 +147,30 @@ Linux|GNU|GNU/*)
LIBC=uclibc
#elif defined(__dietlibc__)
LIBC=dietlibc
+ #elif defined(__GLIBC__)
+ LIBC=gnu
#else
#include <stdarg.h>
+ /* First heuristic to detect musl libc. */
#ifdef __DEFINED_va_list
LIBC=musl
- #else
- LIBC=gnu
#endif
#endif
EOF
- eval "`$CC_FOR_BUILD -E "$dummy.c" 2>/dev/null | grep '^LIBC' | sed 's, ,,g'`"
+ eval "$($CC_FOR_BUILD -E "$dummy.c" 2>/dev/null | grep '^LIBC' | sed 's, ,,g')"
+
+ # Second heuristic to detect musl libc.
+ if [ "$LIBC" = unknown ] &&
+ command -v ldd >/dev/null &&
+ ldd --version 2>&1 | grep -q ^musl; then
+ LIBC=musl
+ fi
+
+ # If the system lacks a compiler, then just pick glibc.
+ # We could probably try harder.
+ if [ "$LIBC" = unknown ]; then
+ LIBC=gnu
+ fi
;;
esac
@@ -177,19 +189,20 @@ case "$UNAME_MACHINE:$UNAME_SYSTEM:$UNAME_RELEASE:$UNAME_VERSION" in
# Note: NetBSD doesn't particularly care about the vendor
# portion of the name. We always set it to "unknown".
sysctl="sysctl -n hw.machine_arch"
- UNAME_MACHINE_ARCH=`(uname -p 2>/dev/null || \
+ UNAME_MACHINE_ARCH=$( (uname -p 2>/dev/null || \
"/sbin/$sysctl" 2>/dev/null || \
"/usr/sbin/$sysctl" 2>/dev/null || \
- echo unknown)`
+ echo unknown))
case "$UNAME_MACHINE_ARCH" in
+ aarch64eb) machine=aarch64_be-unknown ;;
armeb) machine=armeb-unknown ;;
arm*) machine=arm-unknown ;;
sh3el) machine=shl-unknown ;;
sh3eb) machine=sh-unknown ;;
sh5el) machine=sh5le-unknown ;;
earmv*)
- arch=`echo "$UNAME_MACHINE_ARCH" | sed -e 's,^e\(armv[0-9]\).*$,\1,'`
- endian=`echo "$UNAME_MACHINE_ARCH" | sed -ne 's,^.*\(eb\)$,\1,p'`
+ arch=$(echo "$UNAME_MACHINE_ARCH" | sed -e 's,^e\(armv[0-9]\).*$,\1,')
+ endian=$(echo "$UNAME_MACHINE_ARCH" | sed -ne 's,^.*\(eb\)$,\1,p')
machine="${arch}${endian}"-unknown
;;
*) machine="$UNAME_MACHINE_ARCH"-unknown ;;
@@ -220,7 +233,7 @@ case "$UNAME_MACHINE:$UNAME_SYSTEM:$UNAME_RELEASE:$UNAME_VERSION" in
case "$UNAME_MACHINE_ARCH" in
earm*)
expr='s/^earmv[0-9]/-eabi/;s/eb$//'
- abi=`echo "$UNAME_MACHINE_ARCH" | sed -e "$expr"`
+ abi=$(echo "$UNAME_MACHINE_ARCH" | sed -e "$expr")
;;
esac
# The OS release
@@ -233,7 +246,7 @@ case "$UNAME_MACHINE:$UNAME_SYSTEM:$UNAME_RELEASE:$UNAME_VERSION" in
release='-gnu'
;;
*)
- release=`echo "$UNAME_RELEASE" | sed -e 's/[-_].*//' | cut -d. -f1,2`
+ release=$(echo "$UNAME_RELEASE" | sed -e 's/[-_].*//' | cut -d. -f1,2)
;;
esac
# Since CPU_TYPE-MANUFACTURER-KERNEL-OPERATING_SYSTEM:
@@ -242,15 +255,15 @@ case "$UNAME_MACHINE:$UNAME_SYSTEM:$UNAME_RELEASE:$UNAME_VERSION" in
echo "$machine-${os}${release}${abi-}"
exit ;;
*:Bitrig:*:*)
- UNAME_MACHINE_ARCH=`arch | sed 's/Bitrig.//'`
+ UNAME_MACHINE_ARCH=$(arch | sed 's/Bitrig.//')
echo "$UNAME_MACHINE_ARCH"-unknown-bitrig"$UNAME_RELEASE"
exit ;;
*:OpenBSD:*:*)
- UNAME_MACHINE_ARCH=`arch | sed 's/OpenBSD.//'`
+ UNAME_MACHINE_ARCH=$(arch | sed 's/OpenBSD.//')
echo "$UNAME_MACHINE_ARCH"-unknown-openbsd"$UNAME_RELEASE"
exit ;;
*:LibertyBSD:*:*)
- UNAME_MACHINE_ARCH=`arch | sed 's/^.*BSD\.//'`
+ UNAME_MACHINE_ARCH=$(arch | sed 's/^.*BSD\.//')
echo "$UNAME_MACHINE_ARCH"-unknown-libertybsd"$UNAME_RELEASE"
exit ;;
*:MidnightBSD:*:*)
@@ -286,17 +299,17 @@ case "$UNAME_MACHINE:$UNAME_SYSTEM:$UNAME_RELEASE:$UNAME_VERSION" in
alpha:OSF1:*:*)
case $UNAME_RELEASE in
*4.0)
- UNAME_RELEASE=`/usr/sbin/sizer -v | awk '{print $3}'`
+ UNAME_RELEASE=$(/usr/sbin/sizer -v | awk '{print $3}')
;;
*5.*)
- UNAME_RELEASE=`/usr/sbin/sizer -v | awk '{print $4}'`
+ UNAME_RELEASE=$(/usr/sbin/sizer -v | awk '{print $4}')
;;
esac
# According to Compaq, /usr/sbin/psrinfo has been available on
# OSF/1 and Tru64 systems produced since 1995. I hope that
# covers most systems running today. This code pipes the CPU
# types through head -n 1, so we only detect the type of CPU 0.
- ALPHA_CPU_TYPE=`/usr/sbin/psrinfo -v | sed -n -e 's/^ The alpha \(.*\) processor.*$/\1/p' | head -n 1`
+ ALPHA_CPU_TYPE=$(/usr/sbin/psrinfo -v | sed -n -e 's/^ The alpha \(.*\) processor.*$/\1/p' | head -n 1)
case "$ALPHA_CPU_TYPE" in
"EV4 (21064)")
UNAME_MACHINE=alpha ;;
@@ -334,7 +347,7 @@ case "$UNAME_MACHINE:$UNAME_SYSTEM:$UNAME_RELEASE:$UNAME_VERSION" in
# A Tn.n version is a released field test version.
# A Xn.n version is an unreleased experimental baselevel.
# 1.2 uses "1.2" for uname -r.
- echo "$UNAME_MACHINE"-dec-osf"`echo "$UNAME_RELEASE" | sed -e 's/^[PVTX]//' | tr ABCDEFGHIJKLMNOPQRSTUVWXYZ abcdefghijklmnopqrstuvwxyz`"
+ echo "$UNAME_MACHINE"-dec-osf"$(echo "$UNAME_RELEASE" | sed -e 's/^[PVTX]//' | tr ABCDEFGHIJKLMNOPQRSTUVWXYZ abcdefghijklmnopqrstuvwxyz)"
# Reset EXIT trap before exiting to avoid spurious non-zero exit code.
exitcode=$?
trap '' 0
@@ -368,7 +381,7 @@ case "$UNAME_MACHINE:$UNAME_SYSTEM:$UNAME_RELEASE:$UNAME_VERSION" in
exit ;;
Pyramid*:OSx*:*:* | MIS*:OSx*:*:* | MIS*:SMP_DC-OSx*:*:*)
# akee@wpdis03.wpafb.af.mil (Earle F. Ake) contributed MIS and NILE.
- if test "`(/bin/universe) 2>/dev/null`" = att ; then
+ if test "$( (/bin/universe) 2>/dev/null)" = att ; then
echo pyramid-pyramid-sysv3
else
echo pyramid-pyramid-bsd
@@ -381,17 +394,17 @@ case "$UNAME_MACHINE:$UNAME_SYSTEM:$UNAME_RELEASE:$UNAME_VERSION" in
echo sparc-icl-nx6
exit ;;
DRS?6000:UNIX_SV:4.2*:7* | DRS?6000:isis:4.2*:7*)
- case `/usr/bin/uname -p` in
+ case $(/usr/bin/uname -p) in
sparc) echo sparc-icl-nx7; exit ;;
esac ;;
s390x:SunOS:*:*)
- echo "$UNAME_MACHINE"-ibm-solaris2"`echo "$UNAME_RELEASE" | sed -e 's/[^.]*//'`"
+ echo "$UNAME_MACHINE"-ibm-solaris2"$(echo "$UNAME_RELEASE" | sed -e 's/[^.]*//')"
exit ;;
sun4H:SunOS:5.*:*)
- echo sparc-hal-solaris2"`echo "$UNAME_RELEASE"|sed -e 's/[^.]*//'`"
+ echo sparc-hal-solaris2"$(echo "$UNAME_RELEASE"|sed -e 's/[^.]*//')"
exit ;;
sun4*:SunOS:5.*:* | tadpole*:SunOS:5.*:*)
- echo sparc-sun-solaris2"`echo "$UNAME_RELEASE" | sed -e 's/[^.]*//'`"
+ echo sparc-sun-solaris2"$(echo "$UNAME_RELEASE" | sed -e 's/[^.]*//')"
exit ;;
i86pc:AuroraUX:5.*:* | i86xen:AuroraUX:5.*:*)
echo i386-pc-auroraux"$UNAME_RELEASE"
@@ -410,30 +423,30 @@ case "$UNAME_MACHINE:$UNAME_SYSTEM:$UNAME_RELEASE:$UNAME_VERSION" in
SUN_ARCH=x86_64
fi
fi
- echo "$SUN_ARCH"-pc-solaris2"`echo "$UNAME_RELEASE"|sed -e 's/[^.]*//'`"
+ echo "$SUN_ARCH"-pc-solaris2"$(echo "$UNAME_RELEASE"|sed -e 's/[^.]*//')"
exit ;;
sun4*:SunOS:6*:*)
# According to config.sub, this is the proper way to canonicalize
# SunOS6. Hard to guess exactly what SunOS6 will be like, but
# it's likely to be more like Solaris than SunOS4.
- echo sparc-sun-solaris3"`echo "$UNAME_RELEASE"|sed -e 's/[^.]*//'`"
+ echo sparc-sun-solaris3"$(echo "$UNAME_RELEASE"|sed -e 's/[^.]*//')"
exit ;;
sun4*:SunOS:*:*)
- case "`/usr/bin/arch -k`" in
+ case "$(/usr/bin/arch -k)" in
Series*|S4*)
- UNAME_RELEASE=`uname -v`
+ UNAME_RELEASE=$(uname -v)
;;
esac
# Japanese Language versions have a version number like `4.1.3-JL'.
- echo sparc-sun-sunos"`echo "$UNAME_RELEASE"|sed -e 's/-/_/'`"
+ echo sparc-sun-sunos"$(echo "$UNAME_RELEASE"|sed -e 's/-/_/')"
exit ;;
sun3*:SunOS:*:*)
echo m68k-sun-sunos"$UNAME_RELEASE"
exit ;;
sun*:*:4.2BSD:*)
- UNAME_RELEASE=`(sed 1q /etc/motd | awk '{print substr($5,1,3)}') 2>/dev/null`
+ UNAME_RELEASE=$( (sed 1q /etc/motd | awk '{print substr($5,1,3)}') 2>/dev/null)
test "x$UNAME_RELEASE" = x && UNAME_RELEASE=3
- case "`/bin/arch`" in
+ case "$(/bin/arch)" in
sun3)
echo m68k-sun-sunos"$UNAME_RELEASE"
;;
@@ -513,8 +526,8 @@ case "$UNAME_MACHINE:$UNAME_SYSTEM:$UNAME_RELEASE:$UNAME_VERSION" in
}
EOF
$CC_FOR_BUILD -o "$dummy" "$dummy.c" &&
- dummyarg=`echo "$UNAME_RELEASE" | sed -n 's/\([0-9]*\).*/\1/p'` &&
- SYSTEM_NAME=`"$dummy" "$dummyarg"` &&
+ dummyarg=$(echo "$UNAME_RELEASE" | sed -n 's/\([0-9]*\).*/\1/p') &&
+ SYSTEM_NAME=$("$dummy" "$dummyarg") &&
{ echo "$SYSTEM_NAME"; exit; }
echo mips-mips-riscos"$UNAME_RELEASE"
exit ;;
@@ -541,7 +554,7 @@ EOF
exit ;;
AViiON:dgux:*:*)
# DG/UX returns AViiON for all architectures
- UNAME_PROCESSOR=`/usr/bin/uname -p`
+ UNAME_PROCESSOR=$(/usr/bin/uname -p)
if test "$UNAME_PROCESSOR" = mc88100 || test "$UNAME_PROCESSOR" = mc88110
then
if test "$TARGET_BINARY_INTERFACE"x = m88kdguxelfx || \
@@ -569,17 +582,17 @@ EOF
echo m68k-tektronix-bsd
exit ;;
*:IRIX*:*:*)
- echo mips-sgi-irix"`echo "$UNAME_RELEASE"|sed -e 's/-/_/g'`"
+ echo mips-sgi-irix"$(echo "$UNAME_RELEASE"|sed -e 's/-/_/g')"
exit ;;
????????:AIX?:[12].1:2) # AIX 2.2.1 or AIX 2.1.1 is RT/PC AIX.
echo romp-ibm-aix # uname -m gives an 8 hex-code CPU id
- exit ;; # Note that: echo "'`uname -s`'" gives 'AIX '
+ exit ;; # Note that: echo "'$(uname -s)'" gives 'AIX '
i*86:AIX:*:*)
echo i386-ibm-aix
exit ;;
ia64:AIX:*:*)
if test -x /usr/bin/oslevel ; then
- IBM_REV=`/usr/bin/oslevel`
+ IBM_REV=$(/usr/bin/oslevel)
else
IBM_REV="$UNAME_VERSION.$UNAME_RELEASE"
fi
@@ -599,7 +612,7 @@ EOF
exit(0);
}
EOF
- if $CC_FOR_BUILD -o "$dummy" "$dummy.c" && SYSTEM_NAME=`"$dummy"`
+ if $CC_FOR_BUILD -o "$dummy" "$dummy.c" && SYSTEM_NAME=$("$dummy")
then
echo "$SYSTEM_NAME"
else
@@ -612,15 +625,15 @@ EOF
fi
exit ;;
*:AIX:*:[4567])
- IBM_CPU_ID=`/usr/sbin/lsdev -C -c processor -S available | sed 1q | awk '{ print $1 }'`
+ IBM_CPU_ID=$(/usr/sbin/lsdev -C -c processor -S available | sed 1q | awk '{ print $1 }')
if /usr/sbin/lsattr -El "$IBM_CPU_ID" | grep ' POWER' >/dev/null 2>&1; then
IBM_ARCH=rs6000
else
IBM_ARCH=powerpc
fi
if test -x /usr/bin/lslpp ; then
- IBM_REV=`/usr/bin/lslpp -Lqc bos.rte.libc |
- awk -F: '{ print $3 }' | sed s/[0-9]*$/0/`
+ IBM_REV=$(/usr/bin/lslpp -Lqc bos.rte.libc |
+ awk -F: '{ print $3 }' | sed s/[0-9]*$/0/)
else
IBM_REV="$UNAME_VERSION.$UNAME_RELEASE"
fi
@@ -648,14 +661,14 @@ EOF
echo m68k-hp-bsd4.4
exit ;;
9000/[34678]??:HP-UX:*:*)
- HPUX_REV=`echo "$UNAME_RELEASE"|sed -e 's/[^.]*.[0B]*//'`
+ HPUX_REV=$(echo "$UNAME_RELEASE"|sed -e 's/[^.]*.[0B]*//')
case "$UNAME_MACHINE" in
9000/31?) HP_ARCH=m68000 ;;
9000/[34]??) HP_ARCH=m68k ;;
9000/[678][0-9][0-9])
if test -x /usr/bin/getconf; then
- sc_cpu_version=`/usr/bin/getconf SC_CPU_VERSION 2>/dev/null`
- sc_kernel_bits=`/usr/bin/getconf SC_KERNEL_BITS 2>/dev/null`
+ sc_cpu_version=$(/usr/bin/getconf SC_CPU_VERSION 2>/dev/null)
+ sc_kernel_bits=$(/usr/bin/getconf SC_KERNEL_BITS 2>/dev/null)
case "$sc_cpu_version" in
523) HP_ARCH=hppa1.0 ;; # CPU_PA_RISC1_0
528) HP_ARCH=hppa1.1 ;; # CPU_PA_RISC1_1
@@ -702,7 +715,7 @@ EOF
exit (0);
}
EOF
- (CCOPTS="" $CC_FOR_BUILD -o "$dummy" "$dummy.c" 2>/dev/null) && HP_ARCH=`"$dummy"`
+ (CCOPTS="" $CC_FOR_BUILD -o "$dummy" "$dummy.c" 2>/dev/null) && HP_ARCH=$("$dummy")
test -z "$HP_ARCH" && HP_ARCH=hppa
fi ;;
esac
@@ -730,7 +743,7 @@ EOF
echo "$HP_ARCH"-hp-hpux"$HPUX_REV"
exit ;;
ia64:HP-UX:*:*)
- HPUX_REV=`echo "$UNAME_RELEASE"|sed -e 's/[^.]*.[0B]*//'`
+ HPUX_REV=$(echo "$UNAME_RELEASE"|sed -e 's/[^.]*.[0B]*//')
echo ia64-hp-hpux"$HPUX_REV"
exit ;;
3050*:HI-UX:*:*)
@@ -760,7 +773,7 @@ EOF
exit (0);
}
EOF
- $CC_FOR_BUILD -o "$dummy" "$dummy.c" && SYSTEM_NAME=`"$dummy"` &&
+ $CC_FOR_BUILD -o "$dummy" "$dummy.c" && SYSTEM_NAME=$("$dummy") &&
{ echo "$SYSTEM_NAME"; exit; }
echo unknown-hitachi-hiuxwe2
exit ;;
@@ -829,14 +842,14 @@ EOF
echo craynv-cray-unicosmp"$UNAME_RELEASE" | sed -e 's/\.[^.]*$/.X/'
exit ;;
F30[01]:UNIX_System_V:*:* | F700:UNIX_System_V:*:*)
- FUJITSU_PROC=`uname -m | tr ABCDEFGHIJKLMNOPQRSTUVWXYZ abcdefghijklmnopqrstuvwxyz`
- FUJITSU_SYS=`uname -p | tr ABCDEFGHIJKLMNOPQRSTUVWXYZ abcdefghijklmnopqrstuvwxyz | sed -e 's/\///'`
- FUJITSU_REL=`echo "$UNAME_RELEASE" | sed -e 's/ /_/'`
+ FUJITSU_PROC=$(uname -m | tr ABCDEFGHIJKLMNOPQRSTUVWXYZ abcdefghijklmnopqrstuvwxyz)
+ FUJITSU_SYS=$(uname -p | tr ABCDEFGHIJKLMNOPQRSTUVWXYZ abcdefghijklmnopqrstuvwxyz | sed -e 's/\///')
+ FUJITSU_REL=$(echo "$UNAME_RELEASE" | sed -e 's/ /_/')
echo "${FUJITSU_PROC}-fujitsu-${FUJITSU_SYS}${FUJITSU_REL}"
exit ;;
5000:UNIX_System_V:4.*:*)
- FUJITSU_SYS=`uname -p | tr ABCDEFGHIJKLMNOPQRSTUVWXYZ abcdefghijklmnopqrstuvwxyz | sed -e 's/\///'`
- FUJITSU_REL=`echo "$UNAME_RELEASE" | tr ABCDEFGHIJKLMNOPQRSTUVWXYZ abcdefghijklmnopqrstuvwxyz | sed -e 's/ /_/'`
+ FUJITSU_SYS=$(uname -p | tr ABCDEFGHIJKLMNOPQRSTUVWXYZ abcdefghijklmnopqrstuvwxyz | sed -e 's/\///')
+ FUJITSU_REL=$(echo "$UNAME_RELEASE" | tr ABCDEFGHIJKLMNOPQRSTUVWXYZ abcdefghijklmnopqrstuvwxyz | sed -e 's/ /_/')
echo "sparc-fujitsu-${FUJITSU_SYS}${FUJITSU_REL}"
exit ;;
i*86:BSD/386:*:* | i*86:BSD/OS:*:* | *:Ascend\ Embedded/OS:*:*)
@@ -849,25 +862,25 @@ EOF
echo "$UNAME_MACHINE"-unknown-bsdi"$UNAME_RELEASE"
exit ;;
arm:FreeBSD:*:*)
- UNAME_PROCESSOR=`uname -p`
+ UNAME_PROCESSOR=$(uname -p)
set_cc_for_build
if echo __ARM_PCS_VFP | $CC_FOR_BUILD -E - 2>/dev/null \
| grep -q __ARM_PCS_VFP
then
- echo "${UNAME_PROCESSOR}"-unknown-freebsd"`echo ${UNAME_RELEASE}|sed -e 's/[-(].*//'`"-gnueabi
+ echo "${UNAME_PROCESSOR}"-unknown-freebsd"$(echo ${UNAME_RELEASE}|sed -e 's/[-(].*//')"-gnueabi
else
- echo "${UNAME_PROCESSOR}"-unknown-freebsd"`echo ${UNAME_RELEASE}|sed -e 's/[-(].*//'`"-gnueabihf
+ echo "${UNAME_PROCESSOR}"-unknown-freebsd"$(echo ${UNAME_RELEASE}|sed -e 's/[-(].*//')"-gnueabihf
fi
exit ;;
*:FreeBSD:*:*)
- UNAME_PROCESSOR=`/usr/bin/uname -p`
+ UNAME_PROCESSOR=$(/usr/bin/uname -p)
case "$UNAME_PROCESSOR" in
amd64)
UNAME_PROCESSOR=x86_64 ;;
i386)
UNAME_PROCESSOR=i586 ;;
esac
- echo "$UNAME_PROCESSOR"-unknown-freebsd"`echo "$UNAME_RELEASE"|sed -e 's/[-(].*//'`"
+ echo "$UNAME_PROCESSOR"-unknown-freebsd"$(echo "$UNAME_RELEASE"|sed -e 's/[-(].*//')"
exit ;;
i*:CYGWIN*:*)
echo "$UNAME_MACHINE"-pc-cygwin
@@ -903,15 +916,15 @@ EOF
echo x86_64-pc-cygwin
exit ;;
prep*:SunOS:5.*:*)
- echo powerpcle-unknown-solaris2"`echo "$UNAME_RELEASE"|sed -e 's/[^.]*//'`"
+ echo powerpcle-unknown-solaris2"$(echo "$UNAME_RELEASE"|sed -e 's/[^.]*//')"
exit ;;
*:GNU:*:*)
# the GNU system
- echo "`echo "$UNAME_MACHINE"|sed -e 's,[-/].*$,,'`-unknown-$LIBC`echo "$UNAME_RELEASE"|sed -e 's,/.*$,,'`"
+ echo "$(echo "$UNAME_MACHINE"|sed -e 's,[-/].*$,,')-unknown-$LIBC$(echo "$UNAME_RELEASE"|sed -e 's,/.*$,,')"
exit ;;
*:GNU/*:*:*)
# other systems with GNU libc and userland
- echo "$UNAME_MACHINE-unknown-`echo "$UNAME_SYSTEM" | sed 's,^[^/]*/,,' | tr "[:upper:]" "[:lower:]"``echo "$UNAME_RELEASE"|sed -e 's/[-(].*//'`-$LIBC"
+ echo "$UNAME_MACHINE-unknown-$(echo "$UNAME_SYSTEM" | sed 's,^[^/]*/,,' | tr "[:upper:]" "[:lower:]")$(echo "$UNAME_RELEASE"|sed -e 's/[-(].*//')-$LIBC"
exit ;;
*:Minix:*:*)
echo "$UNAME_MACHINE"-unknown-minix
@@ -924,7 +937,7 @@ EOF
echo "$UNAME_MACHINE"-unknown-linux-"$LIBC"
exit ;;
alpha:Linux:*:*)
- case `sed -n '/^cpu model/s/^.*: \(.*\)/\1/p' /proc/cpuinfo 2>/dev/null` in
+ case $(sed -n '/^cpu model/s/^.*: \(.*\)/\1/p' /proc/cpuinfo 2>/dev/null) in
EV5) UNAME_MACHINE=alphaev5 ;;
EV56) UNAME_MACHINE=alphaev56 ;;
PCA56) UNAME_MACHINE=alphapca56 ;;
@@ -1033,7 +1046,7 @@ EOF
#endif
#endif
EOF
- eval "`$CC_FOR_BUILD -E "$dummy.c" 2>/dev/null | grep '^CPU\|^MIPS_ENDIAN\|^LIBCABI'`"
+ eval "$($CC_FOR_BUILD -E "$dummy.c" 2>/dev/null | grep '^CPU\|^MIPS_ENDIAN\|^LIBCABI')"
test "x$CPU" != x && { echo "$CPU${MIPS_ENDIAN}-unknown-linux-$LIBCABI"; exit; }
;;
mips64el:Linux:*:*)
@@ -1053,7 +1066,7 @@ EOF
exit ;;
parisc:Linux:*:* | hppa:Linux:*:*)
# Look for CPU level
- case `grep '^cpu[^a-z]*:' /proc/cpuinfo 2>/dev/null | cut -d' ' -f2` in
+ case $(grep '^cpu[^a-z]*:' /proc/cpuinfo 2>/dev/null | cut -d' ' -f2) in
PA7*) echo hppa1.1-unknown-linux-"$LIBC" ;;
PA8*) echo hppa2.0-unknown-linux-"$LIBC" ;;
*) echo hppa-unknown-linux-"$LIBC" ;;
@@ -1143,7 +1156,7 @@ EOF
echo "$UNAME_MACHINE"-pc-msdosdjgpp
exit ;;
i*86:*:4.*:*)
- UNAME_REL=`echo "$UNAME_RELEASE" | sed 's/\/MP$//'`
+ UNAME_REL=$(echo "$UNAME_RELEASE" | sed 's/\/MP$//')
if grep Novell /usr/include/link.h >/dev/null 2>/dev/null; then
echo "$UNAME_MACHINE"-univel-sysv"$UNAME_REL"
else
@@ -1152,7 +1165,7 @@ EOF
exit ;;
i*86:*:5:[678]*)
# UnixWare 7.x, OpenUNIX and OpenServer 6.
- case `/bin/uname -X | grep "^Machine"` in
+ case $(/bin/uname -X | grep "^Machine") in
*486*) UNAME_MACHINE=i486 ;;
*Pentium) UNAME_MACHINE=i586 ;;
*Pent*|*Celeron) UNAME_MACHINE=i686 ;;
@@ -1161,10 +1174,10 @@ EOF
exit ;;
i*86:*:3.2:*)
if test -f /usr/options/cb.name; then
- UNAME_REL=`sed -n 's/.*Version //p' </usr/options/cb.name`
+ UNAME_REL=$(sed -n 's/.*Version //p' </usr/options/cb.name)
echo "$UNAME_MACHINE"-pc-isc"$UNAME_REL"
elif /bin/uname -X 2>/dev/null >/dev/null ; then
- UNAME_REL=`(/bin/uname -X|grep Release|sed -e 's/.*= //')`
+ UNAME_REL=$( (/bin/uname -X|grep Release|sed -e 's/.*= //'))
(/bin/uname -X|grep i80486 >/dev/null) && UNAME_MACHINE=i486
(/bin/uname -X|grep '^Machine.*Pentium' >/dev/null) \
&& UNAME_MACHINE=i586
@@ -1214,7 +1227,7 @@ EOF
3[345]??:*:4.0:3.0 | 3[34]??A:*:4.0:3.0 | 3[34]??,*:*:4.0:3.0 | 3[34]??/*:*:4.0:3.0 | 4400:*:4.0:3.0 | 4850:*:4.0:3.0 | SKA40:*:4.0:3.0 | SDS2:*:4.0:3.0 | SHG2:*:4.0:3.0 | S7501*:*:4.0:3.0)
OS_REL=''
test -r /etc/.relid \
- && OS_REL=.`sed -n 's/[^ ]* [^ ]* \([0-9][0-9]\).*/\1/p' < /etc/.relid`
+ && OS_REL=.$(sed -n 's/[^ ]* [^ ]* \([0-9][0-9]\).*/\1/p' < /etc/.relid)
/bin/uname -p 2>/dev/null | grep 86 >/dev/null \
&& { echo i486-ncr-sysv4.3"$OS_REL"; exit; }
/bin/uname -p 2>/dev/null | /bin/grep entium >/dev/null \
@@ -1225,7 +1238,7 @@ EOF
NCR*:*:4.2:* | MPRAS*:*:4.2:*)
OS_REL='.3'
test -r /etc/.relid \
- && OS_REL=.`sed -n 's/[^ ]* [^ ]* \([0-9][0-9]\).*/\1/p' < /etc/.relid`
+ && OS_REL=.$(sed -n 's/[^ ]* [^ ]* \([0-9][0-9]\).*/\1/p' < /etc/.relid)
/bin/uname -p 2>/dev/null | grep 86 >/dev/null \
&& { echo i486-ncr-sysv4.3"$OS_REL"; exit; }
/bin/uname -p 2>/dev/null | /bin/grep entium >/dev/null \
@@ -1258,7 +1271,7 @@ EOF
exit ;;
*:SINIX-*:*:*)
if uname -p 2>/dev/null >/dev/null ; then
- UNAME_MACHINE=`(uname -p) 2>/dev/null`
+ UNAME_MACHINE=$( (uname -p) 2>/dev/null)
echo "$UNAME_MACHINE"-sni-sysv4
else
echo ns32k-sni-sysv
@@ -1344,7 +1357,7 @@ EOF
echo aarch64-apple-darwin"$UNAME_RELEASE"
exit ;;
*:Darwin:*:*)
- UNAME_PROCESSOR=`uname -p`
+ UNAME_PROCESSOR=$(uname -p)
case $UNAME_PROCESSOR in
unknown) UNAME_PROCESSOR=powerpc ;;
esac
@@ -1381,7 +1394,7 @@ EOF
echo "$UNAME_PROCESSOR"-apple-darwin"$UNAME_RELEASE"
exit ;;
*:procnto*:*:* | *:QNX:[0123456789]*:*)
- UNAME_PROCESSOR=`uname -p`
+ UNAME_PROCESSOR=$(uname -p)
if test "$UNAME_PROCESSOR" = x86; then
UNAME_PROCESSOR=i386
UNAME_MACHINE=pc
@@ -1449,10 +1462,10 @@ EOF
echo mips-sei-seiux"$UNAME_RELEASE"
exit ;;
*:DragonFly:*:*)
- echo "$UNAME_MACHINE"-unknown-dragonfly"`echo "$UNAME_RELEASE"|sed -e 's/[-(].*//'`"
+ echo "$UNAME_MACHINE"-unknown-dragonfly"$(echo "$UNAME_RELEASE"|sed -e 's/[-(].*//')"
exit ;;
*:*VMS:*:*)
- UNAME_MACHINE=`(uname -p) 2>/dev/null`
+ UNAME_MACHINE=$( (uname -p) 2>/dev/null)
case "$UNAME_MACHINE" in
A*) echo alpha-dec-vms ; exit ;;
I*) echo ia64-dec-vms ; exit ;;
@@ -1462,7 +1475,7 @@ EOF
echo i386-pc-xenix
exit ;;
i*86:skyos:*:*)
- echo "$UNAME_MACHINE"-pc-skyos"`echo "$UNAME_RELEASE" | sed -e 's/ .*$//'`"
+ echo "$UNAME_MACHINE"-pc-skyos"$(echo "$UNAME_RELEASE" | sed -e 's/ .*$//')"
exit ;;
i*86:rdos:*:*)
echo "$UNAME_MACHINE"-pc-rdos
@@ -1520,7 +1533,7 @@ main ()
#define __ARCHITECTURE__ "m68k"
#endif
int version;
- version=`(hostinfo | sed -n 's/.*NeXT Mach \([0-9]*\).*/\1/p') 2>/dev/null`;
+ version=$( (hostinfo | sed -n 's/.*NeXT Mach \([0-9]*\).*/\1/p') 2>/dev/null);
if (version < 4)
printf ("%s-next-nextstep%d\n", __ARCHITECTURE__, version);
else
@@ -1612,7 +1625,7 @@ main ()
}
EOF
-$CC_FOR_BUILD -o "$dummy" "$dummy.c" 2>/dev/null && SYSTEM_NAME=`$dummy` &&
+$CC_FOR_BUILD -o "$dummy" "$dummy.c" 2>/dev/null && SYSTEM_NAME=$($dummy) &&
{ echo "$SYSTEM_NAME"; exit; }
# Apollos put the system type in the environment.
@@ -1637,14 +1650,14 @@ This script (version $timestamp), has failed to recognize the
operating system you are using. If your script is old, overwrite *all*
copies of config.guess and config.sub with the latest versions from:
- https://git.savannah.gnu.org/gitweb/?p=config.git;a=blob_plain;f=config.guess
+ https://git.savannah.gnu.org/cgit/config.git/plain/config.guess
and
- https://git.savannah.gnu.org/gitweb/?p=config.git;a=blob_plain;f=config.sub
+ https://git.savannah.gnu.org/cgit/config.git/plain/config.sub
EOF
-year=`echo $timestamp | sed 's,-.*,,'`
+year=$(echo $timestamp | sed 's,-.*,,')
# shellcheck disable=SC2003
-if test "`expr "\`date +%Y\`" - "$year"`" -lt 3 ; then
+if test "$(expr "$(date +%Y)" - "$year")" -lt 3 ; then
cat >&2 <<EOF
If $0 has already been updated, send the following data and any
@@ -1653,20 +1666,20 @@ provide the necessary information to handle your system.
config.guess timestamp = $timestamp
-uname -m = `(uname -m) 2>/dev/null || echo unknown`
-uname -r = `(uname -r) 2>/dev/null || echo unknown`
-uname -s = `(uname -s) 2>/dev/null || echo unknown`
-uname -v = `(uname -v) 2>/dev/null || echo unknown`
+uname -m = $( (uname -m) 2>/dev/null || echo unknown)
+uname -r = $( (uname -r) 2>/dev/null || echo unknown)
+uname -s = $( (uname -s) 2>/dev/null || echo unknown)
+uname -v = $( (uname -v) 2>/dev/null || echo unknown)
-/usr/bin/uname -p = `(/usr/bin/uname -p) 2>/dev/null`
-/bin/uname -X = `(/bin/uname -X) 2>/dev/null`
+/usr/bin/uname -p = $( (/usr/bin/uname -p) 2>/dev/null)
+/bin/uname -X = $( (/bin/uname -X) 2>/dev/null)
-hostinfo = `(hostinfo) 2>/dev/null`
-/bin/universe = `(/bin/universe) 2>/dev/null`
-/usr/bin/arch -k = `(/usr/bin/arch -k) 2>/dev/null`
-/bin/arch = `(/bin/arch) 2>/dev/null`
-/usr/bin/oslevel = `(/usr/bin/oslevel) 2>/dev/null`
-/usr/convex/getsysinfo = `(/usr/convex/getsysinfo) 2>/dev/null`
+hostinfo = $( (hostinfo) 2>/dev/null)
+/bin/universe = $( (/bin/universe) 2>/dev/null)
+/usr/bin/arch -k = $( (/usr/bin/arch -k) 2>/dev/null)
+/bin/arch = $( (/bin/arch) 2>/dev/null)
+/usr/bin/oslevel = $( (/usr/bin/oslevel) 2>/dev/null)
+/usr/convex/getsysinfo = $( (/usr/convex/getsysinfo) 2>/dev/null)
UNAME_MACHINE = "$UNAME_MACHINE"
UNAME_RELEASE = "$UNAME_RELEASE"
diff --git a/contrib/unbound/config.sub b/contrib/unbound/config.sub
index 9bc49a7e9223..19c9553b1825 100755
--- a/contrib/unbound/config.sub
+++ b/contrib/unbound/config.sub
@@ -2,7 +2,7 @@
# Configuration validation subroutine script.
# Copyright 1992-2020 Free Software Foundation, Inc.
-timestamp='2020-09-08'
+timestamp='2020-12-02'
# 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
@@ -33,7 +33,7 @@ timestamp='2020-09-08'
# Otherwise, we print the canonical config type on stdout and succeed.
# You can get the latest version of this script from:
-# https://git.savannah.gnu.org/gitweb/?p=config.git;a=blob_plain;f=config.sub
+# https://git.savannah.gnu.org/cgit/config.git/plain/config.sub
# This file is supposed to be the same for all GNU packages
# and recognize all the CPU types, system types and aliases
@@ -50,7 +50,7 @@ timestamp='2020-09-08'
# CPU_TYPE-MANUFACTURER-KERNEL-OPERATING_SYSTEM
# It is wrong to echo any other type of specification.
-me=`echo "$0" | sed -e 's,.*/,,'`
+me=$(echo "$0" | sed -e 's,.*/,,')
usage="\
Usage: $0 [OPTION] CPU-MFR-OPSYS or ALIAS
@@ -769,22 +769,22 @@ case $basic_machine in
vendor=hp
;;
i*86v32)
- cpu=`echo "$1" | sed -e 's/86.*/86/'`
+ cpu=$(echo "$1" | sed -e 's/86.*/86/')
vendor=pc
basic_os=sysv32
;;
i*86v4*)
- cpu=`echo "$1" | sed -e 's/86.*/86/'`
+ cpu=$(echo "$1" | sed -e 's/86.*/86/')
vendor=pc
basic_os=sysv4
;;
i*86v)
- cpu=`echo "$1" | sed -e 's/86.*/86/'`
+ cpu=$(echo "$1" | sed -e 's/86.*/86/')
vendor=pc
basic_os=sysv
;;
i*86sol2)
- cpu=`echo "$1" | sed -e 's/86.*/86/'`
+ cpu=$(echo "$1" | sed -e 's/86.*/86/')
vendor=pc
basic_os=solaris2
;;
@@ -917,7 +917,7 @@ case $basic_machine in
;;
leon-*|leon[3-9]-*)
cpu=sparc
- vendor=`echo "$basic_machine" | sed 's/-.*//'`
+ vendor=$(echo "$basic_machine" | sed 's/-.*//')
;;
*-*)
@@ -1084,7 +1084,7 @@ case $cpu-$vendor in
cpu=mipsisa64sb1el
;;
sh5e[lb]-*)
- cpu=`echo "$cpu" | sed 's/^\(sh.\)e\(.\)$/\1\2e/'`
+ cpu=$(echo "$cpu" | sed 's/^\(sh.\)e\(.\)$/\1\2e/')
;;
spur-*)
cpu=spur
@@ -1102,7 +1102,7 @@ case $cpu-$vendor in
cpu=x86_64
;;
xscale-* | xscalee[bl]-*)
- cpu=`echo "$cpu" | sed 's/^xscale/arm/'`
+ cpu=$(echo "$cpu" | sed 's/^xscale/arm/')
;;
arm64-*)
cpu=aarch64
@@ -1241,6 +1241,7 @@ case $cpu-$vendor in
| sparcv8 | sparcv9 | sparcv9b | sparcv9v | sv1 | sx* \
| spu \
| tahoe \
+ | thumbv7* \
| tic30 | tic4x | tic54x | tic55x | tic6x | tic80 \
| tron \
| ubicom32 \
@@ -1286,11 +1287,15 @@ then
case $basic_os in
gnu/linux*)
kernel=linux
- os=`echo $basic_os | sed -e 's|gnu/linux|gnu|'`
+ os=$(echo $basic_os | sed -e 's|gnu/linux|gnu|')
+ ;;
+ os2-emx)
+ kernel=os2
+ os=$(echo $basic_os | sed -e 's|os2-emx|emx|')
;;
nto-qnx*)
kernel=nto
- os=`echo $basic_os | sed -e 's|nto-qnx|qnx|'`
+ os=$(echo $basic_os | sed -e 's|nto-qnx|qnx|')
;;
*-*)
# shellcheck disable=SC2162
@@ -1301,11 +1306,11 @@ EOF
# Default OS when just kernel was specified
nto*)
kernel=nto
- os=`echo $basic_os | sed -e 's|nto|qnx|'`
+ os=$(echo $basic_os | sed -e 's|nto|qnx|')
;;
linux*)
kernel=linux
- os=`echo $basic_os | sed -e 's|linux|gnu|'`
+ os=$(echo $basic_os | sed -e 's|linux|gnu|')
;;
*)
kernel=
@@ -1326,7 +1331,7 @@ case $os in
os=cnk
;;
solaris1 | solaris1.*)
- os=`echo $os | sed -e 's|solaris1|sunos4|'`
+ os=$(echo $os | sed -e 's|solaris1|sunos4|')
;;
solaris)
os=solaris2
@@ -1355,7 +1360,7 @@ case $os in
os=sco3.2v4
;;
sco3.2.[4-9]*)
- os=`echo $os | sed -e 's/sco3.2./sco3.2v/'`
+ os=$(echo $os | sed -e 's/sco3.2./sco3.2v/')
;;
sco*v* | scout)
# Don't match below
@@ -1385,7 +1390,7 @@ case $os in
os=lynxos
;;
mac[0-9]*)
- os=`echo "$os" | sed -e 's|mac|macos|'`
+ os=$(echo "$os" | sed -e 's|mac|macos|')
;;
opened*)
os=openedition
@@ -1394,10 +1399,10 @@ case $os in
os=os400
;;
sunos5*)
- os=`echo "$os" | sed -e 's|sunos5|solaris2|'`
+ os=$(echo "$os" | sed -e 's|sunos5|solaris2|')
;;
sunos6*)
- os=`echo "$os" | sed -e 's|sunos6|solaris3|'`
+ os=$(echo "$os" | sed -e 's|sunos6|solaris3|')
;;
wince*)
os=wince
@@ -1431,7 +1436,7 @@ case $os in
;;
# Preserve the version number of sinix5.
sinix5.*)
- os=`echo $os | sed -e 's|sinix|sysv|'`
+ os=$(echo $os | sed -e 's|sinix|sysv|')
;;
sinix*)
os=sysv4
@@ -1716,7 +1721,7 @@ case $os in
| skyos* | haiku* | rdos* | toppers* | drops* | es* \
| onefs* | tirtos* | phoenix* | fuchsia* | redox* | bme* \
| midnightbsd* | amdhsa* | unleashed* | emscripten* | wasi* \
- | nsk* | powerunix* | genode* | zvmoe* | qnx* )
+ | nsk* | powerunix* | genode* | zvmoe* | qnx* | emx*)
;;
# This one is extra strict with allowed versions
sco3.2v2 | sco3.2v[4-9]* | sco5v6*)
@@ -1747,6 +1752,8 @@ case $kernel-$os in
;;
nto-qnx*)
;;
+ os2-emx)
+ ;;
*-eabi* | *-gnueabi*)
;;
-*)
diff --git a/contrib/unbound/configure b/contrib/unbound/configure
index 69bc15f97fda..b3c53378ee0f 100755
--- a/contrib/unbound/configure
+++ b/contrib/unbound/configure
@@ -1,6 +1,6 @@
#! /bin/sh
# Guess values for system-dependent variables and create Makefiles.
-# Generated by GNU Autoconf 2.69 for unbound 1.12.0.
+# Generated by GNU Autoconf 2.69 for unbound 1.13.0.
#
# Report bugs to <unbound-bugs@nlnetlabs.nl or https://github.com/NLnetLabs/unbound/issues>.
#
@@ -591,8 +591,8 @@ MAKEFLAGS=
# Identity of this package.
PACKAGE_NAME='unbound'
PACKAGE_TARNAME='unbound'
-PACKAGE_VERSION='1.12.0'
-PACKAGE_STRING='unbound 1.12.0'
+PACKAGE_VERSION='1.13.0'
+PACKAGE_STRING='unbound 1.13.0'
PACKAGE_BUGREPORT='unbound-bugs@nlnetlabs.nl or https://github.com/NLnetLabs/unbound/issues'
PACKAGE_URL=''
@@ -1459,7 +1459,7 @@ if test "$ac_init_help" = "long"; then
# Omit some internal or obsolete options to make the list less imposing.
# This message is too long to be a string in the A/UX 3.1 sh.
cat <<_ACEOF
-\`configure' configures unbound 1.12.0 to adapt to many kinds of systems.
+\`configure' configures unbound 1.13.0 to adapt to many kinds of systems.
Usage: $0 [OPTION]... [VAR=VALUE]...
@@ -1524,7 +1524,7 @@ fi
if test -n "$ac_init_help"; then
case $ac_init_help in
- short | recursive ) echo "Configuration of unbound 1.12.0:";;
+ short | recursive ) echo "Configuration of unbound 1.13.0:";;
esac
cat <<\_ACEOF
@@ -1752,7 +1752,7 @@ fi
test -n "$ac_init_help" && exit $ac_status
if $ac_init_version; then
cat <<\_ACEOF
-unbound configure 1.12.0
+unbound configure 1.13.0
generated by GNU Autoconf 2.69
Copyright (C) 2012 Free Software Foundation, Inc.
@@ -2461,7 +2461,7 @@ cat >config.log <<_ACEOF
This file contains any messages produced by compilers while
running configure, to aid debugging if configure makes a mistake.
-It was created by unbound $as_me 1.12.0, which was
+It was created by unbound $as_me 1.13.0, which was
generated by GNU Autoconf 2.69. Invocation command line was
$ $0 $@
@@ -2811,13 +2811,13 @@ ac_compiler_gnu=$ac_cv_c_compiler_gnu
UNBOUND_VERSION_MAJOR=1
-UNBOUND_VERSION_MINOR=12
+UNBOUND_VERSION_MINOR=13
UNBOUND_VERSION_MICRO=0
LIBUNBOUND_CURRENT=9
-LIBUNBOUND_REVISION=10
+LIBUNBOUND_REVISION=11
LIBUNBOUND_AGE=1
# 1.0.0 had 0:12:0
# 1.0.1 had 0:13:0
@@ -2895,6 +2895,7 @@ LIBUNBOUND_AGE=1
# 1.10.1 had 9:8:1
# 1.11.0 had 9:9:1
# 1.12.0 had 9:10:1
+# 1.13.0 had 9:11:1
# Current -- the number of the binary API that we're implementing
# Revision -- which iteration of the implementation of the binary
@@ -14728,7 +14729,7 @@ $as_echo "no" >&6; }
fi
# Checks for header files.
-for ac_header in stdarg.h stdbool.h netinet/in.h netinet/tcp.h sys/param.h sys/select.h sys/socket.h sys/un.h sys/uio.h sys/resource.h arpa/inet.h syslog.h netdb.h sys/wait.h pwd.h glob.h grp.h login_cap.h winsock2.h ws2tcpip.h endian.h sys/endian.h libkern/OSByteOrder.h sys/ipc.h sys/shm.h ifaddrs.h net/if.h
+for ac_header in stdarg.h stdbool.h netinet/in.h netinet/tcp.h sys/param.h sys/select.h sys/socket.h sys/un.h sys/uio.h sys/resource.h arpa/inet.h syslog.h netdb.h sys/wait.h pwd.h glob.h grp.h login_cap.h winsock2.h ws2tcpip.h endian.h sys/endian.h libkern/OSByteOrder.h sys/ipc.h sys/shm.h ifaddrs.h
do :
as_ac_Header=`$as_echo "ac_cv_header_$ac_header" | $as_tr_sh`
ac_fn_c_check_header_compile "$LINENO" "$ac_header" "$as_ac_Header" "$ac_includes_default
@@ -14742,6 +14743,34 @@ fi
done
+# net/if.h portability for Darwin see:
+# https://www.gnu.org/software/autoconf/manual/autoconf-2.69/html_node/Header-Portability.html
+for ac_header in net/if.h
+do :
+ ac_fn_c_check_header_compile "$LINENO" "net/if.h" "ac_cv_header_net_if_h" "
+#include <stdio.h>
+#ifdef STDC_HEADERS
+# include <stdlib.h>
+# include <stddef.h>
+#else
+# ifdef HAVE_STDLIB_H
+# include <stdlib.h>
+# endif
+#endif
+#ifdef HAVE_SYS_SOCKET_H
+# include <sys/socket.h>
+#endif
+
+"
+if test "x$ac_cv_header_net_if_h" = xyes; then :
+ cat >>confdefs.h <<_ACEOF
+#define HAVE_NET_IF_H 1
+_ACEOF
+
+fi
+
+done
+
# Check for Apple header. This uncovers TARGET_OS_IPHONE, TARGET_OS_TV or TARGET_OS_WATCH
for ac_header in TargetConditionals.h
@@ -21686,7 +21715,7 @@ _ACEOF
-version=1.12.0
+version=1.13.0
date=`date +'%b %e, %Y'`
@@ -22205,7 +22234,7 @@ cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1
# report actual input values of CONFIG_FILES etc. instead of their
# values after options handling.
ac_log="
-This file was extended by unbound $as_me 1.12.0, which was
+This file was extended by unbound $as_me 1.13.0, which was
generated by GNU Autoconf 2.69. Invocation command line was
CONFIG_FILES = $CONFIG_FILES
@@ -22271,7 +22300,7 @@ _ACEOF
cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1
ac_cs_config="`$as_echo "$ac_configure_args" | sed 's/^ //; s/[\\""\`\$]/\\\\&/g'`"
ac_cs_version="\\
-unbound config.status 1.12.0
+unbound config.status 1.13.0
configured by $0, generated by GNU Autoconf 2.69,
with options \\"\$ac_cs_config\\"
diff --git a/contrib/unbound/configure.ac b/contrib/unbound/configure.ac
index 7d987929469a..5385f7747e8e 100644
--- a/contrib/unbound/configure.ac
+++ b/contrib/unbound/configure.ac
@@ -10,7 +10,7 @@ sinclude(dnscrypt/dnscrypt.m4)
# must be numbers. ac_defun because of later processing
m4_define([VERSION_MAJOR],[1])
-m4_define([VERSION_MINOR],[12])
+m4_define([VERSION_MINOR],[13])
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])
@@ -18,7 +18,7 @@ AC_SUBST(UNBOUND_VERSION_MINOR, [VERSION_MINOR])
AC_SUBST(UNBOUND_VERSION_MICRO, [VERSION_MICRO])
LIBUNBOUND_CURRENT=9
-LIBUNBOUND_REVISION=10
+LIBUNBOUND_REVISION=11
LIBUNBOUND_AGE=1
# 1.0.0 had 0:12:0
# 1.0.1 had 0:13:0
@@ -96,6 +96,7 @@ LIBUNBOUND_AGE=1
# 1.10.1 had 9:8:1
# 1.11.0 had 9:9:1
# 1.12.0 had 9:10:1
+# 1.13.0 had 9:11:1
# Current -- the number of the binary API that we're implementing
# Revision -- which iteration of the implementation of the binary
@@ -399,7 +400,23 @@ ACX_LIBTOOL_C_ONLY
PKG_PROG_PKG_CONFIG
# Checks for header files.
-AC_CHECK_HEADERS([stdarg.h stdbool.h netinet/in.h netinet/tcp.h sys/param.h sys/select.h sys/socket.h sys/un.h sys/uio.h sys/resource.h arpa/inet.h syslog.h netdb.h sys/wait.h pwd.h glob.h grp.h login_cap.h winsock2.h ws2tcpip.h endian.h sys/endian.h libkern/OSByteOrder.h sys/ipc.h sys/shm.h ifaddrs.h net/if.h],,, [AC_INCLUDES_DEFAULT])
+AC_CHECK_HEADERS([stdarg.h stdbool.h netinet/in.h netinet/tcp.h sys/param.h sys/select.h sys/socket.h sys/un.h sys/uio.h sys/resource.h arpa/inet.h syslog.h netdb.h sys/wait.h pwd.h glob.h grp.h login_cap.h winsock2.h ws2tcpip.h endian.h sys/endian.h libkern/OSByteOrder.h sys/ipc.h sys/shm.h ifaddrs.h],,, [AC_INCLUDES_DEFAULT])
+# net/if.h portability for Darwin see:
+# https://www.gnu.org/software/autoconf/manual/autoconf-2.69/html_node/Header-Portability.html
+AC_CHECK_HEADERS([net/if.h],,, [
+#include <stdio.h>
+#ifdef STDC_HEADERS
+# include <stdlib.h>
+# include <stddef.h>
+#else
+# ifdef HAVE_STDLIB_H
+# include <stdlib.h>
+# endif
+#endif
+#ifdef HAVE_SYS_SOCKET_H
+# include <sys/socket.h>
+#endif
+])
# Check for Apple header. This uncovers TARGET_OS_IPHONE, TARGET_OS_TV or TARGET_OS_WATCH
AC_CHECK_HEADERS([TargetConditionals.h])
diff --git a/contrib/unbound/contrib/README b/contrib/unbound/contrib/README
index 9db078e5617c..ef2a0ab885dd 100644
--- a/contrib/unbound/contrib/README
+++ b/contrib/unbound/contrib/README
@@ -53,3 +53,5 @@ distribution but may be helpful.
lookups for downstream clients.
* drop2rpz: perl script that converts the Spamhaus DROP-List in RPZ-Format,
contributed by Andreas Schulze.
+* metrics.awk: awk script that can convert unbound-control stats to
+ Prometheus metrics format output.
diff --git a/contrib/unbound/contrib/metrics.awk b/contrib/unbound/contrib/metrics.awk
new file mode 100644
index 000000000000..5a7a2569c29a
--- /dev/null
+++ b/contrib/unbound/contrib/metrics.awk
@@ -0,0 +1,180 @@
+# read output of unbound-control stats
+# and output prometheus metrics style output.
+# use these options:
+# server: extended-statistics: yes
+# statistics-cumulative: no
+# statistics-interval: 0
+# remote-control: control-enable: yes
+# Can use it like unbound-control stats | awk -f "metrics.awk"
+
+BEGIN {
+ FS="=";
+}
+# everything like total.num.queries=value is put in val["total.num.queries"]
+/^.*\..*=/ {
+ val[$1]=$2;
+}
+# print the output metrics
+END {
+ print "# HELP unbound_hits_queries Unbound DNS traffic and cache hits"
+ print "# TYPE unbound_hits_queries gauge"
+ print "unbound_hits_queries{type=\"total.num.queries\"} " val["total.num.queries"];
+ for (x=0; x<99; x++) {
+ if(val["thread" $x ".num.queries"] != "") {
+ print "unbound_hits_queries{type=\"thread" $x ".num.queries\"} " val["thread" $x ".num.queries"];
+ }
+ }
+ print "unbound_hits_queries{type=\"total.num.cachehits\"} " val["total.num.cachehits"];
+ print "unbound_hits_queries{type=\"total.num.prefetch\"} " val["total.num.prefetch"];
+ print "unbound_hits_queries{type=\"num.query.tcp\"} " val["num.query.tcp"];
+ print "unbound_hits_queries{type=\"num.query.tcpout\"} " val["num.query.tcpout"];
+ print "unbound_hits_queries{type=\"num.query.tls\"} " val["num.query.tls"];
+ print "unbound_hits_queries{type=\"num.query.tls.resume\"} " val["num.query.tls.resume"];
+ print "unbound_hits_queries{type=\"num.query.ipv6\"} " val["num.query.ipv6"];
+ print "unbound_hits_queries{type=\"unwanted.queries\"} " val["unwanted.queries"];
+ print ""
+
+ print "# HELP unbound_queue_queries Unbound requestlist size"
+ print "# TYPE unbound_queue_queries gauge"
+ print "unbound_queue_queries{type=\"total.requestlist.avg\"} " val["total.requestlist.avg"];
+ print "unbound_queue_queries{type=\"total.requestlist.max\"} " val["total.requestlist.max"];
+ print "unbound_queue_queries{type=\"total.requestlist.overwritten\"} " val["total.requestlist.overwritten"];
+ print "unbound_queue_queries{type=\"total.requestlist.exceeded\"} " val["total.requestlist.exceeded"];
+ print ""
+
+ print "# HELP unbound_memory_bytes Unbound memory usage"
+ print "# TYPE unbound_memory_bytes gauge"
+ print "unbound_memory_bytes{type=\"mem.cache.rrset\"} " val["mem.cache.rrset"];
+ print "unbound_memory_bytes{type=\"mem.cache.message\"} " val["mem.cache.message"];
+ print "unbound_memory_bytes{type=\"mem.mod.iterator\"} " val["mem.mod.iterator"];
+ if(val["mem.mod.validator"] != "") {
+ print "unbound_memory_bytes{type=\"mem.mod.validator\"} " val["mem.mod.validator"];
+ }
+ if(val["mem.mod.respip"] != "") {
+ print "unbound_memory_bytes{type=\"mem.mod.respip\"} " val["mem.mod.respip"];
+ }
+ if(val["mem.mod.subnet"] != "") {
+ print "unbound_memory_bytes{type=\"mem.mod.subnet\"} " val["mem.mod.subnet"];
+ }
+ if(val["mem.mod.ipsecmod"] != "") {
+ print "unbound_memory_bytes{type=\"mem.mod.ipsecmod\"} " val["mem.mod.ipsecmod"];
+ }
+ if(val["mem.mod.dynlibmod"] != "") {
+ print "unbound_memory_bytes{type=\"mem.mod.dynlibmod\"} " val["mem.mod.dynlibmod"];
+ }
+ print "unbound_memory_bytes{type=\"msg.cache.count\"} " val["msg.cache.count"];
+ print "unbound_memory_bytes{type=\"rrset.cache.count\"} " val["rrset.cache.count"];
+ print "unbound_memory_bytes{type=\"infra.cache.count\"} " val["infra.cache.count"];
+ print "unbound_memory_bytes{type=\"key.cache.count\"} " val["key.cache.count"];
+ print ""
+
+ print "# HELP unbound_by_type_queries Unbound DNS queries by type"
+ print "# TYPE unbound_by_type_queries gauge"
+ for(x in val) {
+ if(x ~ /^num.query.type./) {
+ if(val[x] != "") {
+ split(x, a, ".");
+ print "unbound_by_type_queries{type=\"" a[4] "\"} " val[x];
+ }
+ }
+ }
+ print ""
+
+ print "# HELP unbound_by_class_queries Unbound DNS queries by class"
+ print "# TYPE unbound_by_class_queries gauge"
+ for(x in val) {
+ if(x ~ /^num.query.class./) {
+ if(val[x] != "") {
+ split(x, a, ".");
+ print "unbound_by_class_queries{class=\"" a[4] "\"} " val[x];
+ }
+ }
+ }
+ print ""
+
+ print "# HELP unbound_by_opcode_queries Unbound DNS queries by opcode"
+ print "# TYPE unbound_by_opcode_queries gauge"
+ for(x in val) {
+ if(x ~ /^num.query.opcode./) {
+ if(val[x] != "") {
+ split(x, a, ".");
+ print "unbound_by_opcode_queries{opcode=\"" a[4] "\"} " val[x];
+ }
+ }
+ }
+ print ""
+
+ print "# HELP unbound_by_rcode_queries Unbound DNS answers by rcode"
+ print "# TYPE unbound_by_rcode_queries gauge"
+ for(x in val) {
+ if(x ~ /^num.answer.rcode./) {
+ if(val[x] != "") {
+ split(x, a, ".");
+ print "unbound_by_rcode_queries{rcode=\"" a[4] "\"} " val[x];
+ }
+ }
+ }
+ print ""
+
+ print "# HELP unbound_by_flags_queries Unbound DNS queries by flags"
+ print "# TYPE unbound_by_flags_queries gauge"
+ for(x in val) {
+ if(x ~ /^num.query.flags./) {
+ if(val[x] != "") {
+ split(x, a, ".");
+ print "unbound_by_flags_queries{flag=\"" a[4] "\"} " val[x];
+ }
+ }
+ }
+ if(val["num.query.edns.present"] != "") {
+ print "unbound_by_flags_queries{flag=\"num.query.edns.present\"} " val["num.query.edns.present"];
+ }
+ if(val["num.query.edns.DO"] != "") {
+ print "unbound_by_flags_queries{flag=\"num.query.edns.DO\"} " val["num.query.edns.DO"];
+ }
+ print ""
+
+ print "# HELP unbound_histogram_seconds Unbound DNS histogram of reply time"
+ print "# TYPE unbound_histogram_seconds gauge"
+ print "unbound_histogram_seconds{bucket=\"000000.000000.to.000000.000001\"} " val["histogram.000000.000000.to.000000.000001"];
+ print "unbound_histogram_seconds{bucket=\"000000.000001.to.000000.000002\"} " val["histogram.000000.000001.to.000000.000002"];
+ print "unbound_histogram_seconds{bucket=\"000000.000002.to.000000.000004\"} " val["histogram.000000.000002.to.000000.000004"];
+ print "unbound_histogram_seconds{bucket=\"000000.000004.to.000000.000008\"} " val["histogram.000000.000004.to.000000.000008"];
+ print "unbound_histogram_seconds{bucket=\"000000.000008.to.000000.000016\"} " val["histogram.000000.000008.to.000000.000016"];
+ print "unbound_histogram_seconds{bucket=\"000000.000016.to.000000.000032\"} " val["histogram.000000.000016.to.000000.000032"];
+ print "unbound_histogram_seconds{bucket=\"000000.000032.to.000000.000064\"} " val["histogram.000000.000032.to.000000.000064"];
+ print "unbound_histogram_seconds{bucket=\"000000.000064.to.000000.000128\"} " val["histogram.000000.000064.to.000000.000128"];
+ print "unbound_histogram_seconds{bucket=\"000000.000128.to.000000.000256\"} " val["histogram.000000.000128.to.000000.000256"];
+ print "unbound_histogram_seconds{bucket=\"000000.000256.to.000000.000512\"} " val["histogram.000000.000256.to.000000.000512"];
+ print "unbound_histogram_seconds{bucket=\"000000.000512.to.000000.001024\"} " val["histogram.000000.000512.to.000000.001024"];
+ print "unbound_histogram_seconds{bucket=\"000000.001024.to.000000.002048\"} " val["histogram.000000.001024.to.000000.002048"];
+ print "unbound_histogram_seconds{bucket=\"000000.002048.to.000000.004096\"} " val["histogram.000000.002048.to.000000.004096"];
+ print "unbound_histogram_seconds{bucket=\"000000.004096.to.000000.008192\"} " val["histogram.000000.004096.to.000000.008192"];
+ print "unbound_histogram_seconds{bucket=\"000000.008192.to.000000.016384\"} " val["histogram.000000.008192.to.000000.016384"];
+ print "unbound_histogram_seconds{bucket=\"000000.016384.to.000000.032768\"} " val["histogram.000000.016384.to.000000.032768"];
+ print "unbound_histogram_seconds{bucket=\"000000.032768.to.000000.065536\"} " val["histogram.000000.032768.to.000000.065536"];
+ print "unbound_histogram_seconds{bucket=\"000000.065536.to.000000.131072\"} " val["histogram.000000.065536.to.000000.131072"];
+ print "unbound_histogram_seconds{bucket=\"000000.131072.to.000000.262144\"} " val["histogram.000000.131072.to.000000.262144"];
+ print "unbound_histogram_seconds{bucket=\"000000.262144.to.000000.524288\"} " val["histogram.000000.262144.to.000000.524288"];
+ print "unbound_histogram_seconds{bucket=\"000000.524288.to.000001.000000\"} " val["histogram.000000.524288.to.000001.000000"];
+ print "unbound_histogram_seconds{bucket=\"000001.000000.to.000002.000000\"} " val["histogram.000001.000000.to.000002.000000"];
+ print "unbound_histogram_seconds{bucket=\"000002.000000.to.000004.000000\"} " val["histogram.000002.000000.to.000004.000000"];
+ print "unbound_histogram_seconds{bucket=\"000004.000000.to.000008.000000\"} " val["histogram.000004.000000.to.000008.000000"];
+ print "unbound_histogram_seconds{bucket=\"000008.000000.to.000016.000000\"} " val["histogram.000008.000000.to.000016.000000"];
+ print "unbound_histogram_seconds{bucket=\"000016.000000.to.000032.000000\"} " val["histogram.000016.000000.to.000032.000000"];
+ print "unbound_histogram_seconds{bucket=\"000032.000000.to.000064.000000\"} " val["histogram.000032.000000.to.000064.000000"];
+ print "unbound_histogram_seconds{bucket=\"000064.000000.to.000128.000000\"} " val["histogram.000064.000000.to.000128.000000"];
+ print "unbound_histogram_seconds{bucket=\"000128.000000.to.000256.000000\"} " val["histogram.000128.000000.to.000256.000000"];
+ print "unbound_histogram_seconds{bucket=\"000256.000000.to.000512.000000\"} " val["histogram.000256.000000.to.000512.000000"];
+ print "unbound_histogram_seconds{bucket=\"000512.000000.to.001024.000000\"} " val["histogram.000512.000000.to.001024.000000"];
+ print "unbound_histogram_seconds{bucket=\"001024.000000.to.002048.000000\"} " val["histogram.001024.000000.to.002048.000000"];
+ print "unbound_histogram_seconds{bucket=\"002048.000000.to.004096.000000\"} " val["histogram.002048.000000.to.004096.000000"];
+ print "unbound_histogram_seconds{bucket=\"004096.000000.to.008192.000000\"} " val["histogram.004096.000000.to.008192.000000"];
+ print "unbound_histogram_seconds{bucket=\"008192.000000.to.016384.000000\"} " val["histogram.008192.000000.to.016384.000000"];
+ print "unbound_histogram_seconds{bucket=\"016384.000000.to.032768.000000\"} " val["histogram.016384.000000.to.032768.000000"];
+ print "unbound_histogram_seconds{bucket=\"032768.000000.to.065536.000000\"} " val["histogram.032768.000000.to.065536.000000"];
+ print "unbound_histogram_seconds{bucket=\"065536.000000.to.131072.000000\"} " val["histogram.065536.000000.to.131072.000000"];
+ print "unbound_histogram_seconds{bucket=\"131072.000000.to.262144.000000\"} " val["histogram.131072.000000.to.262144.000000"];
+ print "unbound_histogram_seconds{bucket=\"262144.000000.to.524288.000000\"} " val["histogram.262144.000000.to.524288.000000"];
+ print ""
+}
diff --git a/contrib/unbound/contrib/unbound.service.in b/contrib/unbound/contrib/unbound.service.in
index c95ab94b343a..a4596978dbe2 100644
--- a/contrib/unbound/contrib/unbound.service.in
+++ b/contrib/unbound/contrib/unbound.service.in
@@ -66,7 +66,7 @@ ProtectSystem=strict
RuntimeDirectory=unbound
ConfigurationDirectory=unbound
StateDirectory=unbound
-RestrictAddressFamilies=AF_INET AF_INET6 AF_UNIX
+RestrictAddressFamilies=AF_INET AF_INET6 AF_NETLINK AF_UNIX
RestrictRealtime=true
SystemCallArchitectures=native
SystemCallFilter=~@clock @cpu-emulation @debug @keyring @module mount @obsolete @resources
diff --git a/contrib/unbound/contrib/unbound_portable.service.in b/contrib/unbound/contrib/unbound_portable.service.in
index 998b66dec999..e763763f02e1 100644
--- a/contrib/unbound/contrib/unbound_portable.service.in
+++ b/contrib/unbound/contrib/unbound_portable.service.in
@@ -38,7 +38,7 @@ ProtectSystem=strict
RuntimeDirectory=unbound
ConfigurationDirectory=unbound
StateDirectory=unbound
-RestrictAddressFamilies=AF_INET AF_INET6 AF_UNIX
+RestrictAddressFamilies=AF_INET AF_INET6 AF_NETLINK AF_UNIX
RestrictRealtime=true
SystemCallArchitectures=native
SystemCallFilter=~@clock @cpu-emulation @debug @keyring @module mount @obsolete @resources
diff --git a/contrib/unbound/daemon/daemon.c b/contrib/unbound/daemon/daemon.c
index f480c94e61f6..a11d50a9ba93 100644
--- a/contrib/unbound/daemon/daemon.c
+++ b/contrib/unbound/daemon/daemon.c
@@ -291,7 +291,7 @@ daemon_init(void)
free(daemon);
return NULL;
}
- if(!(daemon->env->edns_tags = edns_tags_create())) {
+ if(!(daemon->env->edns_strings = edns_strings_create())) {
auth_zones_delete(daemon->env->auth_zones);
acl_list_delete(daemon->acl);
tcl_list_delete(daemon->tcl);
@@ -638,9 +638,9 @@ daemon_fork(struct daemon* daemon)
&daemon->use_rpz))
fatal_exit("auth_zones could not be setup");
- /* Set-up EDNS tags */
- if(!edns_tags_apply_cfg(daemon->env->edns_tags, daemon->cfg))
- fatal_exit("Could not set up EDNS tags");
+ /* Set-up EDNS strings */
+ if(!edns_strings_apply_cfg(daemon->env->edns_strings, daemon->cfg))
+ fatal_exit("Could not set up EDNS strings");
/* setup modules */
daemon_setup_modules(daemon);
@@ -773,7 +773,7 @@ daemon_delete(struct daemon* daemon)
rrset_cache_delete(daemon->env->rrset_cache);
infra_delete(daemon->env->infra_cache);
edns_known_options_delete(daemon->env);
- edns_tags_delete(daemon->env->edns_tags);
+ edns_strings_delete(daemon->env->edns_strings);
auth_zones_delete(daemon->env->auth_zones);
}
ub_randfree(daemon->rand);
diff --git a/contrib/unbound/daemon/unbound.c b/contrib/unbound/daemon/unbound.c
index cd0fd69f2ca4..bc6d2bc9efc5 100644
--- a/contrib/unbound/daemon/unbound.c
+++ b/contrib/unbound/daemon/unbound.c
@@ -337,22 +337,44 @@ readpid (const char* file)
/** write pid to file.
* @param pidfile: file name of pid file.
* @param pid: pid to write to file.
+ * @return false on failure
*/
-static void
+static int
writepid (const char* pidfile, pid_t pid)
{
- FILE* f;
+ int fd;
+ char pidbuf[32];
+ size_t count = 0;
+ snprintf(pidbuf, sizeof(pidbuf), "%lu\n", (unsigned long)pid);
- if ((f = fopen(pidfile, "w")) == NULL ) {
+ if((fd = open(pidfile, O_WRONLY | O_CREAT | O_TRUNC
+#ifdef O_NOFOLLOW
+ | O_NOFOLLOW
+#endif
+ , 0644)) == -1) {
log_err("cannot open pidfile %s: %s",
pidfile, strerror(errno));
- return;
+ return 0;
}
- if(fprintf(f, "%lu\n", (unsigned long)pid) < 0) {
- log_err("cannot write to pidfile %s: %s",
- pidfile, strerror(errno));
+ while(count < strlen(pidbuf)) {
+ ssize_t r = write(fd, pidbuf+count, strlen(pidbuf)-count);
+ if(r == -1) {
+ if(errno == EAGAIN || errno == EINTR)
+ continue;
+ log_err("cannot write to pidfile %s: %s",
+ pidfile, strerror(errno));
+ close(fd);
+ return 0;
+ } else if(r == 0) {
+ log_err("cannot write any bytes to pidfile %s: "
+ "write returns 0 bytes written", pidfile);
+ close(fd);
+ return 0;
+ }
+ count += r;
}
- fclose(f);
+ close(fd);
+ return 1;
}
/**
@@ -506,16 +528,17 @@ perform_setup(struct daemon* daemon, struct config_file* cfg, int debug_mode,
/* write new pidfile (while still root, so can be outside chroot) */
#ifdef HAVE_KILL
if(cfg->pidfile && cfg->pidfile[0] && need_pidfile) {
- writepid(daemon->pidfile, getpid());
- if(cfg->username && cfg->username[0] && cfg_uid != (uid_t)-1 &&
- pidinchroot) {
+ if(writepid(daemon->pidfile, getpid())) {
+ if(cfg->username && cfg->username[0] && cfg_uid != (uid_t)-1 &&
+ pidinchroot) {
# ifdef HAVE_CHOWN
- if(chown(daemon->pidfile, cfg_uid, cfg_gid) == -1) {
- verbose(VERB_QUERY, "cannot chown %u.%u %s: %s",
- (unsigned)cfg_uid, (unsigned)cfg_gid,
- daemon->pidfile, strerror(errno));
- }
+ if(chown(daemon->pidfile, cfg_uid, cfg_gid) == -1) {
+ verbose(VERB_QUERY, "cannot chown %u.%u %s: %s",
+ (unsigned)cfg_uid, (unsigned)cfg_gid,
+ daemon->pidfile, strerror(errno));
+ }
# endif /* HAVE_CHOWN */
+ }
}
}
#else
diff --git a/contrib/unbound/daemon/worker.c b/contrib/unbound/daemon/worker.c
index 5ad8ce4e4094..76c4bb5b1e76 100644
--- a/contrib/unbound/daemon/worker.c
+++ b/contrib/unbound/daemon/worker.c
@@ -576,7 +576,7 @@ apply_respip_action(struct worker* worker, const struct query_info* qinfo,
struct comm_reply* repinfo, struct ub_packed_rrset_key** alias_rrset,
struct reply_info** encode_repp, struct auth_zones* az)
{
- struct respip_action_info actinfo = {0};
+ struct respip_action_info actinfo = {0, 0, 0, 0, NULL, 0, NULL};
actinfo.action = respip_none;
if(qinfo->qtype != LDNS_RR_TYPE_A &&
@@ -1789,8 +1789,8 @@ worker_init(struct worker* worker, struct config_file *cfg,
? cfg->tcp_keepalive_timeout
: cfg->tcp_idle_timeout,
cfg->harden_large_queries, cfg->http_max_streams,
- cfg->http_endpoint, worker->daemon->tcl,
- worker->daemon->listen_sslctx,
+ cfg->http_endpoint, cfg->http_notls_downstream,
+ worker->daemon->tcl, worker->daemon->listen_sslctx,
dtenv, worker_handle_request, worker);
if(!worker->front) {
log_err("could not create listening sockets");
@@ -1807,7 +1807,7 @@ worker_init(struct worker* worker, struct config_file *cfg,
&worker_alloc_cleanup, worker,
cfg->do_udp || cfg->udp_upstream_without_downstream,
worker->daemon->connect_sslctx, cfg->delay_close,
- cfg->tls_use_sni, dtenv);
+ cfg->tls_use_sni, dtenv, cfg->udp_connect);
if(!worker->back) {
log_err("could not create outgoing sockets");
worker_delete(worker);
diff --git a/contrib/unbound/dnstap/dnstap.c b/contrib/unbound/dnstap/dnstap.c
index 0c8c6c4d462a..b8a3216703c1 100644
--- a/contrib/unbound/dnstap/dnstap.c
+++ b/contrib/unbound/dnstap/dnstap.c
@@ -134,15 +134,13 @@ dt_create(struct config_file* cfg)
if(cfg->dnstap && cfg->dnstap_socket_path && cfg->dnstap_socket_path[0] &&
(cfg->dnstap_ip==NULL || cfg->dnstap_ip[0]==0)) {
- char* p = fname_after_chroot(cfg->dnstap_socket_path, cfg, 1);
- if(!p) {
- log_err("malloc failure");
- return NULL;
- }
+ char* p = cfg->dnstap_socket_path;
+ if(cfg->chrootdir && cfg->chrootdir[0] && strncmp(p,
+ cfg->chrootdir, strlen(cfg->chrootdir)) == 0)
+ p += strlen(cfg->chrootdir);
verbose(VERB_OPS, "attempting to connect to dnstap socket %s",
p);
check_socket_file(p);
- free(p);
}
env = (struct dt_env *) calloc(1, sizeof(struct dt_env));
diff --git a/contrib/unbound/dnstap/dtstream.c b/contrib/unbound/dnstap/dtstream.c
index b0918c52cc63..f1ace3c34023 100644
--- a/contrib/unbound/dnstap/dtstream.c
+++ b/contrib/unbound/dnstap/dtstream.c
@@ -341,15 +341,19 @@ int dt_io_thread_apply_cfg(struct dt_io_thread* dtio, struct config_file *cfg)
dtio->is_bidirectional = cfg->dnstap_bidirectional;
if(dtio->upstream_is_unix) {
+ char* nm;
if(!cfg->dnstap_socket_path ||
cfg->dnstap_socket_path[0]==0) {
log_err("dnstap setup: no dnstap-socket-path for "
"socket connect");
return 0;
}
+ nm = cfg->dnstap_socket_path;
+ if(cfg->chrootdir && cfg->chrootdir[0] && strncmp(nm,
+ cfg->chrootdir, strlen(cfg->chrootdir)) == 0)
+ nm += strlen(cfg->chrootdir);
free(dtio->socket_path);
- dtio->socket_path = fname_after_chroot(cfg->dnstap_socket_path,
- cfg, 1);
+ dtio->socket_path = strdup(nm);
if(!dtio->socket_path) {
log_err("dnstap setup: malloc failure");
return 0;
diff --git a/contrib/unbound/doc/Changelog b/contrib/unbound/doc/Changelog
index 87f796398993..1622dd2b5e27 100644
--- a/contrib/unbound/doc/Changelog
+++ b/contrib/unbound/doc/Changelog
@@ -1,3 +1,166 @@
+30 November 2020: Wouter
+ - Fix assertion failure on double callback when iterator loses
+ interest in query at head of line that then has the tcp stream
+ not kept for reuse.
+ - tag for the 1.13.0rc4 release.
+
+27 November 2020: Wouter
+ - Fix compile warning for type cast in http2_submit_dns_response.
+ - Fix when use free buffer to initialize rbtree for stream reuse.
+ - Fix compile warnings for windows.
+ - Fix compile warnings in rpz initialization.
+ - Fix contrib/metrics.awk for FreeBSD awk compatibility.
+ - tag for the 1.13.0rc3 release.
+
+26 November 2020: Wouter
+ - Fix to omit UDP receive errors from log, if verbosity low.
+ These happen because of udp-connect.
+ - For #352: contrib/metrics.awk for Prometheus style metrics output.
+ - Fix that after failed read, the readagain cannot activate.
+ - Clear readagain upon decommission of pending tcp structure.
+
+25 November 2020: Wouter
+ - with udp-connect ignore connection refused with UDP timeouts.
+ - Fix udp-connect on FreeBSD, do send calls on connected UDP socket.
+ - Better fix for reuse tree comparison for is-tls sockets. Where
+ the tree key identity is preserved after cleanup of the TLS state.
+ - Remove debug commands from reuse tests.
+ - Fix memory leak for edns client tag opcode config element.
+ - Attempt fix for libevent state in tcp reuse cases after a packet
+ is written.
+ - Fix readagain and writeagain callback functions for comm point
+ cleanup.
+ - tag for the 1.13.0rc2 release.
+
+24 November 2020: Wouter
+ - Merge PR #283 : Stream reuse. This implements upstream stream
+ reuse for performing several queries over the same TCP or TLS
+ channel.
+ - set version of main branch to 1.13.0 for upcoming release.
+ - iana portlist updated.
+ - Fix one port unit test for udp-connect.
+ - tag for the 1.13.0rc1 release.
+ - Fix crash when TLS connection is closed prematurely, when
+ reuse tree comparison is not properly identical to insertion.
+ - Fix padding of struct regional for 32bit systems.
+
+23 November 2020: George
+ - Merge PR #313 from Ralph Dolmans: Replace edns-client-tag with
+ edns-client-string option.
+
+23 November 2020: Wouter
+ - Merge #351 from dvzrv: Add AF_NETLINK to set of allowed socket
+ address families.
+ - Fix #350: with the AF_NETLINK permission, to fix 1.12.0 error:
+ failed to list interfaces: getifaddrs: Address family not
+ supported by protocol.
+ - Fix #347: IP_DONTFRAG broken on Apple xcode 12.2.
+ - Option to toggle udp-connect, default is enabled.
+ - Fix for #303 CVE-2020-28935 : Fix that symlink does not interfere
+ with chown of pidfile.
+ - Further fix for it and retvalue 0 fix for it.
+
+12 November 2020: Wouter
+ - Fix to connect() to UDP destinations, default turned on,
+ this lowers vulnerability to ICMP side channels.
+ - Retry for interfaces with unused ports if possible.
+
+10 November 2020: Wouter
+ - Fix #341: fixing a possible memory leak.
+ - Fix memory leak after fix for possible memory leak failure.
+ - Fix #343: Fail to build --with-libnghttp2 with error: 'SSIZE_MAX'
+ undeclared.
+
+27 October 2020: Wouter
+ - In man page note that tls-cert-bundle is read before permission
+ drop and chroot.
+
+22 October 2020: Wouter
+ - Fix #333: Unbound Segmentation Fault w/ log_info Functions From
+ Python Mod.
+ - Fix that minimal-responses does not remove addresses from a priming
+ query response.
+
+21 October 2020: George
+ - Fix #327: net/if.h check fails on some darwin versions; contribution by
+ Joshua Root.
+ - Fix #320: potential memory corruption due to size miscomputation upton
+ custom region alloc init.
+
+21 October 2020: Wouter
+ - Merge PR #228 : infra-keep-probing option to probe hosts that are
+ down. Add infra-keep-probing: yes option. Hosts that are down are
+ probed more frequently.
+ With the option turned on, it probes about every 120 seconds,
+ eventually after exponential backoff, and that keeps that way. If
+ traffic keeps up for the domain. It probes with one at a time, eg.
+ one query is allowed to probe, other queries within that 120 second
+ interval are turned away.
+
+19 October 2020: George
+ - Merge PR #324 from James Renken: Add modern X.509v3 extensions to
+ unbound-control TLS certificates.
+ - Fix for PR #324 to attach the x509v3 extensions to the client
+ certificate.
+
+19 October 2020: Ralph
+ - local-zone regional allocations outside of chunk
+
+19 October 2020: Wouter
+ - Fix that http settings have colon in set_option, for
+ http-endpoint, http-max-streams, http-query-buffer-size,
+ http-response-buffer-size, and http-nodelay.
+ - Fix memory leak of https port string when reading config.
+ - Fix #330: [Feature request] Add unencrypted DNS over HTTPS support.
+ This adds the option http-notls-downstream: yesno to change that,
+ and the dohclient test code has the -n option.
+ - Fix python documentation warning on functions.rst inplace_cb_reply.
+ - Fix dnstap test to wait for log timer to see if queries are logged.
+ - Log ip address when http session recv fails, eg. due to tls fail.
+ - Fix to set the tcp handler event toggle flag back to default when
+ the handler structure is reused.
+ - Clean the fix for out of order TCP processing limits on number
+ of queries. It was tested to work.
+
+16 October 2020: Wouter
+ - Fix that the out of order TCP processing does not limit the
+ number of outstanding queries over a connection.
+
+15 October 2020: George
+ - Fix that if there are reply callbacks for the given rcode, those
+ are called per reply and a new message created if that was modified
+ by the call.
+ - Pass the comm_reply information to the inplace_cb_reply* functions
+ during the mesh state and update the documentation on that.
+
+15 October 2020: Wouter
+ - Merge PR #326 from netblue30: DoH: implement content-length
+ header field
+ - DoH content length, simplify code, remove declaration after
+ statement and fix cast warning.
+
+14 October 2020: Wouter
+ - Fix for python reply callback to see mesh state reply_list member,
+ it only removes it briefly for the commpoint call so that it does
+ not drop it and attempt to modify the reply list during reply.
+ - Fix that if there are on reply callbacks, those are called per
+ reply and a new message created if that was modified by the call.
+ - Free up auth zone parse region after use for lookup of host
+
+13 October 2020: Wouter
+ - Fix #323: unbound testsuite fails on mock build in systemd-nspawn
+ if systemd support is build.
+
+9 October 2020: Wouter
+ - Fix dnstap socket and the chroot not applied properly to the dnstap
+ socket path.
+ - Fix warning in libnss compile, nss_buf2dsa is not used without DSA.
+
+8 October 2020: Wouter
+ - Tag for 1.12.0 release.
+ - Current repo is version 1.12.1 in development.
+ - Fix #319: potential memory leak on config failure, in rpz config.
+
1 October 2020: Wouter
- Current repo is version 1.12.0 for release. Tag for 1.12.0rc1.
diff --git a/contrib/unbound/doc/README b/contrib/unbound/doc/README
index c6ff31a6fac3..e864bb188e33 100644
--- a/contrib/unbound/doc/README
+++ b/contrib/unbound/doc/README
@@ -1,4 +1,4 @@
-README for Unbound 1.12.0
+README for Unbound 1.13.0
Copyright 2007 NLnet Labs
http://unbound.net
diff --git a/contrib/unbound/doc/example.conf.in b/contrib/unbound/doc/example.conf.in
index 2fe9a2c7e7a7..82ccaa4dd9f9 100644
--- a/contrib/unbound/doc/example.conf.in
+++ b/contrib/unbound/doc/example.conf.in
@@ -1,7 +1,7 @@
#
# Example configuration file.
#
-# See unbound.conf(5) man page, version 1.12.0.
+# See unbound.conf(5) man page, version 1.13.0.
#
# this is a comment.
@@ -161,6 +161,9 @@ server:
# msec to wait before close of port on timeout UDP. 0 disables.
# delay-close: 0
+ # perform connect for UDP sockets to mitigate ICMP side channel.
+ # udp-connect: yes
+
# 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
@@ -192,6 +195,9 @@ server:
# minimum wait time for responses, increase if uplink is long. In msec.
# infra-cache-min-rtt: 50
+ # enable to make server probe down hosts more frequently.
+ # infra-keep-probing: no
+
# the number of slabs to use for the Infrastructure cache.
# the number of slabs must be a power of 2.
# more slabs reduce lock contention, but fragment memory usage.
@@ -788,6 +794,9 @@ server:
# service.
# http-nodelay: yes
+ # Disable TLS for DNS-over-HTTP downstream service.
+ # http-notls-downstream: no
+
# DNS64 prefix. Must be specified when DNS64 is use.
# Enable dns64 in module-config. Used to synthesize IPv6 from IPv4.
# dns64-prefix: 64:ff9b::0/96
diff --git a/contrib/unbound/doc/libunbound.3.in b/contrib/unbound/doc/libunbound.3.in
index 34778ee5c09e..80f7335be05e 100644
--- a/contrib/unbound/doc/libunbound.3.in
+++ b/contrib/unbound/doc/libunbound.3.in
@@ -1,4 +1,4 @@
-.TH "libunbound" "3" "Oct 8, 2020" "NLnet Labs" "unbound 1.12.0"
+.TH "libunbound" "3" "Dec 3, 2020" "NLnet Labs" "unbound 1.13.0"
.\"
.\" libunbound.3 -- unbound library functions manual
.\"
@@ -44,7 +44,7 @@
.B ub_ctx_zone_remove,
.B ub_ctx_data_add,
.B ub_ctx_data_remove
-\- Unbound DNS validating resolver 1.12.0 functions.
+\- Unbound DNS validating resolver 1.13.0 functions.
.SH "SYNOPSIS"
.B #include <unbound.h>
.LP
diff --git a/contrib/unbound/doc/unbound-anchor.8.in b/contrib/unbound/doc/unbound-anchor.8.in
index 21f12ebeff1c..564420da04a7 100644
--- a/contrib/unbound/doc/unbound-anchor.8.in
+++ b/contrib/unbound/doc/unbound-anchor.8.in
@@ -1,4 +1,4 @@
-.TH "unbound-anchor" "8" "Oct 8, 2020" "NLnet Labs" "unbound 1.12.0"
+.TH "unbound-anchor" "8" "Dec 3, 2020" "NLnet Labs" "unbound 1.13.0"
.\"
.\" unbound-anchor.8 -- unbound anchor maintenance utility manual
.\"
diff --git a/contrib/unbound/doc/unbound-checkconf.8.in b/contrib/unbound/doc/unbound-checkconf.8.in
index 55abe6004027..abcd45c8b811 100644
--- a/contrib/unbound/doc/unbound-checkconf.8.in
+++ b/contrib/unbound/doc/unbound-checkconf.8.in
@@ -1,4 +1,4 @@
-.TH "unbound-checkconf" "8" "Oct 8, 2020" "NLnet Labs" "unbound 1.12.0"
+.TH "unbound-checkconf" "8" "Dec 3, 2020" "NLnet Labs" "unbound 1.13.0"
.\"
.\" unbound-checkconf.8 -- unbound configuration checker manual
.\"
diff --git a/contrib/unbound/doc/unbound-control.8.in b/contrib/unbound/doc/unbound-control.8.in
index f82b62d3d9b6..f63a2f49cee4 100644
--- a/contrib/unbound/doc/unbound-control.8.in
+++ b/contrib/unbound/doc/unbound-control.8.in
@@ -1,4 +1,4 @@
-.TH "unbound-control" "8" "Oct 8, 2020" "NLnet Labs" "unbound 1.12.0"
+.TH "unbound-control" "8" "Dec 3, 2020" "NLnet Labs" "unbound 1.13.0"
.\"
.\" unbound-control.8 -- unbound remote control manual
.\"
diff --git a/contrib/unbound/doc/unbound-host.1.in b/contrib/unbound/doc/unbound-host.1.in
index d3b502d92657..e0cc704d39df 100644
--- a/contrib/unbound/doc/unbound-host.1.in
+++ b/contrib/unbound/doc/unbound-host.1.in
@@ -1,4 +1,4 @@
-.TH "unbound\-host" "1" "Oct 8, 2020" "NLnet Labs" "unbound 1.12.0"
+.TH "unbound\-host" "1" "Dec 3, 2020" "NLnet Labs" "unbound 1.13.0"
.\"
.\" unbound-host.1 -- unbound DNS lookup utility
.\"
diff --git a/contrib/unbound/doc/unbound.8.in b/contrib/unbound/doc/unbound.8.in
index 44a9879e5872..c012e379eb40 100644
--- a/contrib/unbound/doc/unbound.8.in
+++ b/contrib/unbound/doc/unbound.8.in
@@ -1,4 +1,4 @@
-.TH "unbound" "8" "Oct 8, 2020" "NLnet Labs" "unbound 1.12.0"
+.TH "unbound" "8" "Dec 3, 2020" "NLnet Labs" "unbound 1.13.0"
.\"
.\" unbound.8 -- unbound manual
.\"
@@ -9,7 +9,7 @@
.\"
.SH "NAME"
.B unbound
-\- Unbound DNS validating resolver 1.12.0.
+\- Unbound DNS validating resolver 1.13.0.
.SH "SYNOPSIS"
.B unbound
.RB [ \-h ]
diff --git a/contrib/unbound/doc/unbound.conf.5.in b/contrib/unbound/doc/unbound.conf.5.in
index bcbc9f205333..a244eee7a70e 100644
--- a/contrib/unbound/doc/unbound.conf.5.in
+++ b/contrib/unbound/doc/unbound.conf.5.in
@@ -1,4 +1,4 @@
-.TH "unbound.conf" "5" "Oct 8, 2020" "NLnet Labs" "unbound 1.12.0"
+.TH "unbound.conf" "5" "Dec 3, 2020" "NLnet Labs" "unbound 1.13.0"
.\"
.\" unbound.conf.5 -- unbound.conf manual
.\"
@@ -274,6 +274,10 @@ eg. 1500 msec. When timeouts happen you need extra sockets, it checks
the ID and remote IP of packets, and unwanted packets are added to the
unwanted packet counter.
.TP
+.B udp\-connect: \fI<yes or no>
+Perform connect for UDP sockets that mitigates ICMP side channel leakage.
+Default is yes.
+.TP
.B unknown\-server\-time\-limit: \fI<msec>
The wait time in msec for waiting for an unknown server to reply.
Increase this if you are behind a slow satellite link, to eg. 1128.
@@ -382,6 +386,12 @@ Lower limit for dynamic retransmit timeout calculation in infrastructure
cache. Default is 50 milliseconds. Increase this value if using forwarders
needing more time to do recursive name resolution.
.TP
+.B infra\-keep\-probing: \fI<yes or no>
+If enabled the server keeps probing hosts that are down, in the one probe
+at a time regime. Default is no. Hosts that are down, eg. they did
+not respond during the one probe at a time period, are marked as down and
+it may take \fBinfra\-host\-ttl\fR time to get probed again.
+.TP
.B define\-tag: \fI<"list of tags">
Define the tags that can be used with local\-zone and access\-control.
Enclose the list between quotes ("") and put spaces between tags.
@@ -516,7 +526,8 @@ Alternate syntax for \fBtls\-port\fR.
If null or "", no file is used. Set it to the certificate bundle file,
for example "/etc/pki/tls/certs/ca\-bundle.crt". These certificates are used
for authenticating connections made to outside peers. For example auth\-zone
-urls, and also DNS over TLS connections.
+urls, and also DNS over TLS connections. It is read at start up before
+permission drop and chroot.
.TP
.B ssl\-cert\-bundle: \fI<file>
Alternate syntax for \fBtls\-cert\-bundle\fR.
@@ -587,6 +598,10 @@ megabytes or gigabytes (1024*1024 bytes in a megabyte).
Set TCP_NODELAY socket option on sockets used to provide DNS-over-HTTPS service.
Ignored if the option is not available. Default is yes.
.TP
+.B http\-notls\-downstream: \fI<yes or no>
+Disable use of TLS for the downstream DNS-over-HTTP connections. Useful for
+local back end servers. Default is no.
+.TP
.B use\-systemd: \fI<yes or no>
Enable or disable systemd socket activation.
Default is no.
@@ -1535,15 +1550,15 @@ Set the number of servers that should be used for fast server selection. Only
use the fastest specified number of servers with the fast\-server\-permil
option, that turns this on or off. The default is to use the fastest 3 servers.
.TP 5
-.B edns\-client\-tag: \fI<IP netblock> <tag data>
-Include an edns-client-tag option in queries with destination address matching
-the configured IP netblock. This configuration option can be used multiple
-times. The most specific match will be used. The tag data is configured in
-decimal format, from 0 to 65535.
+.B edns\-client\-string: \fI<IP netblock> <string>
+Include an EDNS0 option containing configured ascii string in queries with
+destination address matching the configured IP netblock. This configuration
+option can be used multiple times. The most specific match will be used.
.TP 5
-.B edns\-client\-tag\-opcode: \fI<opcode>
-EDNS0 option code for the edns-client-tag option, from 0 to 65535. Default is
-16, as assigned by IANA.
+.B edns\-client\-string\-opcode: \fI<opcode>
+EDNS0 option code for the \fIedns\-client\-string\fR option, from 0 to 65535.
+A value from the `Reserved for Local/Experimental` range (65001-65534) should
+be used. Default is 65001.
.SS "Remote Control Options"
In the
.B remote\-control:
diff --git a/contrib/unbound/libunbound/context.c b/contrib/unbound/libunbound/context.c
index 713259c718ce..cff2831a77cd 100644
--- a/contrib/unbound/libunbound/context.c
+++ b/contrib/unbound/libunbound/context.c
@@ -80,7 +80,7 @@ context_finalize(struct ub_ctx* ctx)
return UB_INITFAIL;
if(!auth_zones_apply_cfg(ctx->env->auth_zones, cfg, 1, &is_rpz))
return UB_INITFAIL;
- if(!edns_tags_apply_cfg(ctx->env->edns_tags, cfg))
+ if(!edns_strings_apply_cfg(ctx->env->edns_strings, cfg))
return UB_INITFAIL;
if(!slabhash_is_size(ctx->env->msg_cache, cfg->msg_cache_size,
cfg->msg_cache_slabs)) {
diff --git a/contrib/unbound/libunbound/libunbound.c b/contrib/unbound/libunbound/libunbound.c
index 3922eb0417f8..c9e24ba8d8f2 100644
--- a/contrib/unbound/libunbound/libunbound.c
+++ b/contrib/unbound/libunbound/libunbound.c
@@ -154,8 +154,8 @@ static struct ub_ctx* ub_ctx_create_nopipe(void)
errno = ENOMEM;
return NULL;
}
- ctx->env->edns_tags = edns_tags_create();
- if(!ctx->env->edns_tags) {
+ ctx->env->edns_strings = edns_strings_create();
+ if(!ctx->env->edns_strings) {
auth_zones_delete(ctx->env->auth_zones);
edns_known_options_delete(ctx->env);
config_delete(ctx->env->cfg);
@@ -186,7 +186,7 @@ ub_ctx_create(void)
config_delete(ctx->env->cfg);
modstack_desetup(&ctx->mods, ctx->env);
edns_known_options_delete(ctx->env);
- edns_tags_delete(ctx->env->edns_tags);
+ edns_strings_delete(ctx->env->edns_strings);
free(ctx->env);
free(ctx);
errno = e;
@@ -199,7 +199,7 @@ ub_ctx_create(void)
config_delete(ctx->env->cfg);
modstack_desetup(&ctx->mods, ctx->env);
edns_known_options_delete(ctx->env);
- edns_tags_delete(ctx->env->edns_tags);
+ edns_strings_delete(ctx->env->edns_strings);
free(ctx->env);
free(ctx);
errno = e;
@@ -338,7 +338,7 @@ ub_ctx_delete(struct ub_ctx* ctx)
infra_delete(ctx->env->infra_cache);
config_delete(ctx->env->cfg);
edns_known_options_delete(ctx->env);
- edns_tags_delete(ctx->env->edns_tags);
+ edns_strings_delete(ctx->env->edns_strings);
auth_zones_delete(ctx->env->auth_zones);
free(ctx->env);
}
diff --git a/contrib/unbound/libunbound/libworker.c b/contrib/unbound/libunbound/libworker.c
index bd42462e1be6..06cbb8869f61 100644
--- a/contrib/unbound/libunbound/libworker.c
+++ b/contrib/unbound/libunbound/libworker.c
@@ -238,7 +238,7 @@ libworker_setup(struct ub_ctx* ctx, int is_bg, struct ub_event_base* eb)
ports, numports, cfg->unwanted_threshold,
cfg->outgoing_tcp_mss, &libworker_alloc_cleanup, w,
cfg->do_udp || cfg->udp_upstream_without_downstream, w->sslctx,
- cfg->delay_close, cfg->tls_use_sni, NULL);
+ cfg->delay_close, cfg->tls_use_sni, NULL, cfg->udp_connect);
w->env->outnet = w->back;
if(!w->is_bg || w->is_bg_thread) {
lock_basic_unlock(&ctx->cfglock);
diff --git a/contrib/unbound/respip/respip.c b/contrib/unbound/respip/respip.c
index 6fa4f18851fd..9ee098def820 100644
--- a/contrib/unbound/respip/respip.c
+++ b/contrib/unbound/respip/respip.c
@@ -914,7 +914,7 @@ respip_rewrite_reply(const struct query_info* qinfo,
int ret = 1;
struct ub_packed_rrset_key* redirect_rrset = NULL;
struct rpz* r;
- struct auth_zone* a;
+ struct auth_zone* a = NULL;
struct ub_packed_rrset_key* data = NULL;
int rpz_used = 0;
int rpz_log = 0;
@@ -1109,7 +1109,7 @@ respip_operate(struct module_qstate* qstate, enum module_ev event, int id,
qstate->return_msg && qstate->return_msg->rep) {
struct reply_info* new_rep = qstate->return_msg->rep;
struct ub_packed_rrset_key* alias_rrset = NULL;
- struct respip_action_info actinfo = {0};
+ struct respip_action_info actinfo = {0, 0, 0, 0, NULL, 0, NULL};
actinfo.action = respip_none;
if(!respip_rewrite_reply(&qstate->qinfo,
@@ -1170,7 +1170,7 @@ respip_merge_cname(struct reply_info* base_rep,
struct ub_packed_rrset_key* alias_rrset = NULL; /* ditto */
uint16_t tgt_rcode;
size_t i, j;
- struct respip_action_info actinfo = {0};
+ struct respip_action_info actinfo = {0, 0, 0, 0, NULL, 0, NULL};
actinfo.action = respip_none;
/* If the query for the CNAME target would result in an unusual rcode,
diff --git a/contrib/unbound/services/authzone.c b/contrib/unbound/services/authzone.c
index 5064d2c61080..8fa69d27aa21 100644
--- a/contrib/unbound/services/authzone.c
+++ b/contrib/unbound/services/authzone.c
@@ -5387,6 +5387,7 @@ void auth_xfer_transfer_lookup_callback(void* arg, int rcode, sldns_buffer* buf,
verbose(VERB_ALGO, "auth zone %s host %s type %s transfer lookup has no answer", zname, xfr->task_transfer->lookup_target->host, (xfr->task_transfer->lookup_aaaa?"AAAA":"A"));
}
}
+ regional_free_all(temp);
} else {
if(verbosity >= VERB_ALGO) {
char zname[255+1];
@@ -6444,6 +6445,7 @@ void auth_xfer_probe_lookup_callback(void* arg, int rcode, sldns_buffer* buf,
verbose(VERB_ALGO, "auth zone %s host %s type %s probe lookup has no address", zname, xfr->task_probe->lookup_target->host, (xfr->task_probe->lookup_aaaa?"AAAA":"A"));
}
}
+ regional_free_all(temp);
} else {
if(verbosity >= VERB_ALGO) {
char zname[255+1];
diff --git a/contrib/unbound/services/cache/infra.c b/contrib/unbound/services/cache/infra.c
index c2484a9f1aa8..2d16bcd6e405 100644
--- a/contrib/unbound/services/cache/infra.c
+++ b/contrib/unbound/services/cache/infra.c
@@ -244,6 +244,7 @@ infra_create(struct config_file* cfg)
return NULL;
}
infra->host_ttl = cfg->host_ttl;
+ infra->infra_keep_probing = cfg->infra_keep_probing;
infra_dp_ratelimit = cfg->ratelimit;
infra->domain_rates = slabhash_create(cfg->ratelimit_slabs,
INFRA_HOST_STARTSIZE, cfg->ratelimit_size,
@@ -297,6 +298,7 @@ infra_adjust(struct infra_cache* infra, struct config_file* cfg)
if(!infra)
return infra_create(cfg);
infra->host_ttl = cfg->host_ttl;
+ infra->infra_keep_probing = cfg->infra_keep_probing;
infra_dp_ratelimit = cfg->ratelimit;
infra_ip_ratelimit = cfg->ip_ratelimit;
maxmem = cfg->infra_cache_numhosts * (sizeof(struct infra_key)+
@@ -445,6 +447,7 @@ infra_host(struct infra_cache* infra, struct sockaddr_storage* addr,
if(e && ((struct infra_data*)e->data)->ttl < timenow) {
/* it expired, try to reuse existing entry */
int old = ((struct infra_data*)e->data)->rtt.rto;
+ time_t tprobe = ((struct infra_data*)e->data)->probedelay;
uint8_t tA = ((struct infra_data*)e->data)->timeout_A;
uint8_t tAAAA = ((struct infra_data*)e->data)->timeout_AAAA;
uint8_t tother = ((struct infra_data*)e->data)->timeout_other;
@@ -460,6 +463,7 @@ infra_host(struct infra_cache* infra, struct sockaddr_storage* addr,
if(old >= USEFUL_SERVER_TOP_TIMEOUT) {
((struct infra_data*)e->data)->rtt.rto
= USEFUL_SERVER_TOP_TIMEOUT;
+ ((struct infra_data*)e->data)->probedelay = tprobe;
((struct infra_data*)e->data)->timeout_A = tA;
((struct infra_data*)e->data)->timeout_AAAA = tAAAA;
((struct infra_data*)e->data)->timeout_other = tother;
@@ -482,7 +486,8 @@ infra_host(struct infra_cache* infra, struct sockaddr_storage* addr,
*edns_vs = data->edns_version;
*edns_lame_known = data->edns_lame_known;
*to = rtt_timeout(&data->rtt);
- if(*to >= PROBE_MAXRTO && rtt_notimeout(&data->rtt)*4 <= *to) {
+ if(*to >= PROBE_MAXRTO && (infra->infra_keep_probing ||
+ rtt_notimeout(&data->rtt)*4 <= *to)) {
/* delay other queries, this is the probe query */
if(!wr) {
lock_rw_unlock(&e->lock);
@@ -566,18 +571,27 @@ infra_rtt_update(struct infra_cache* infra, struct sockaddr_storage* addr,
struct lruhash_entry* e = infra_lookup_nottl(infra, addr, addrlen,
nm, nmlen, 1);
struct infra_data* data;
- int needtoinsert = 0;
+ int needtoinsert = 0, expired = 0;
int rto = 1;
+ time_t oldprobedelay = 0;
if(!e) {
if(!(e = new_entry(infra, addr, addrlen, nm, nmlen, timenow)))
return 0;
needtoinsert = 1;
} else if(((struct infra_data*)e->data)->ttl < timenow) {
+ oldprobedelay = ((struct infra_data*)e->data)->probedelay;
data_entry_init(infra, e, timenow);
+ expired = 1;
}
/* have an entry, update the rtt */
data = (struct infra_data*)e->data;
if(roundtrip == -1) {
+ if(needtoinsert || expired) {
+ /* timeout on entry that has expired before the timer
+ * keep old timeout from the function caller */
+ data->rtt.rto = orig_rtt;
+ data->probedelay = oldprobedelay;
+ }
rtt_lost(&data->rtt, orig_rtt);
if(qtype == LDNS_RR_TYPE_A) {
if(data->timeout_A < TIMEOUT_COUNT_MAX)
@@ -681,7 +695,12 @@ infra_get_lame_rtt(struct infra_cache* infra,
return 0;
host = (struct infra_data*)e->data;
*rtt = rtt_unclamped(&host->rtt);
- if(host->rtt.rto >= PROBE_MAXRTO && timenow < host->probedelay
+ if(host->rtt.rto >= PROBE_MAXRTO && timenow >= host->probedelay
+ && infra->infra_keep_probing) {
+ /* single probe, keep probing */
+ if(*rtt >= USEFUL_SERVER_TOP_TIMEOUT)
+ *rtt = USEFUL_SERVER_TOP_TIMEOUT-1000;
+ } else if(host->rtt.rto >= PROBE_MAXRTO && timenow < host->probedelay
&& rtt_notimeout(&host->rtt)*4 <= host->rtt.rto) {
/* single probe for this domain, and we are not probing */
/* unless the query type allows a probe to happen */
@@ -704,7 +723,8 @@ infra_get_lame_rtt(struct infra_cache* infra,
/* see if this can be a re-probe of an unresponsive server */
/* minus 1000 because that is outside of the RTTBAND, so
* blacklisted servers stay blacklisted if this is chosen */
- if(host->rtt.rto >= USEFUL_SERVER_TOP_TIMEOUT) {
+ if(host->rtt.rto >= USEFUL_SERVER_TOP_TIMEOUT ||
+ infra->infra_keep_probing) {
lock_rw_unlock(&e->lock);
*rtt = USEFUL_SERVER_TOP_TIMEOUT-1000;
*lame = 0;
diff --git a/contrib/unbound/services/cache/infra.h b/contrib/unbound/services/cache/infra.h
index e33f2a6c04ee..14f97c4c64d3 100644
--- a/contrib/unbound/services/cache/infra.h
+++ b/contrib/unbound/services/cache/infra.h
@@ -114,6 +114,8 @@ struct infra_cache {
struct slabhash* hosts;
/** TTL value for host information, in seconds */
int host_ttl;
+ /** the hosts that are down are kept probed for recovery */
+ int infra_keep_probing;
/** hash table with query rates per name: rate_key, rate_data */
struct slabhash* domain_rates;
/** ratelimit settings for domains, struct domain_limit_data */
diff --git a/contrib/unbound/services/listen_dnsport.c b/contrib/unbound/services/listen_dnsport.c
index 3a98c264297a..d63c0e0aab00 100644
--- a/contrib/unbound/services/listen_dnsport.c
+++ b/contrib/unbound/services/listen_dnsport.c
@@ -43,6 +43,7 @@
# include <sys/types.h>
#endif
#include <sys/time.h>
+#include <limits.h>
#ifdef USE_TCP_FASTOPEN
#include <netinet/tcp.h>
#endif
@@ -81,9 +82,6 @@
/** number of queued TCP connections for listen() */
#define TCP_BACKLOG 256
-/** number of simultaneous requests a client can have */
-#define TCP_MAX_REQ_SIMULTANEOUS 32
-
#ifndef THREADS_DISABLED
/** lock on the counter of stream buffer memory */
static lock_basic_type stream_wait_count_lock;
@@ -533,7 +531,9 @@ create_udp_sock(int family, int socktype, struct sockaddr* addr,
return -1;
}
}
-# elif defined(IP_DONTFRAG)
+# elif defined(IP_DONTFRAG) && !defined(__APPLE__)
+ /* the IP_DONTFRAG option if defined in the 11.0 OSX headers,
+ * but does not work on that version, so we exclude it */
int off = 0;
if (setsockopt(s, IPPROTO_IP, IP_DONTFRAG,
&off, (socklen_t)sizeof(off)) < 0) {
@@ -1244,8 +1244,9 @@ struct listen_dnsport*
listen_create(struct comm_base* base, struct listen_port* ports,
size_t bufsize, int tcp_accept_count, int tcp_idle_timeout,
int harden_large_queries, uint32_t http_max_streams,
- char* http_endpoint, struct tcl_list* tcp_conn_limit, void* sslctx,
- struct dt_env* dtenv, comm_point_callback_type* cb, void *cb_arg)
+ char* http_endpoint, int http_notls, struct tcl_list* tcp_conn_limit,
+ void* sslctx, struct dt_env* dtenv, comm_point_callback_type* cb,
+ void *cb_arg)
{
struct listen_dnsport* front = (struct listen_dnsport*)
malloc(sizeof(struct listen_dnsport));
@@ -1295,15 +1296,19 @@ listen_create(struct comm_base* base, struct listen_port* ports,
http_max_streams, http_endpoint,
tcp_conn_limit, bufsize, front->udp_buff,
ports->ftype, cb, cb_arg);
- cp->ssl = sslctx;
+ if(http_notls && ports->ftype == listen_type_http)
+ cp->ssl = NULL;
+ else
+ cp->ssl = sslctx;
if(ports->ftype == listen_type_http) {
- if(!sslctx) {
- log_warn("HTTPS port configured, but no TLS "
+ if(!sslctx && !http_notls) {
+ log_warn("HTTPS port configured, but no TLS "
"tls-service-key or tls-service-pem "
"set");
}
#ifndef HAVE_SSL_CTX_SET_ALPN_SELECT_CB
- log_warn("Unbound is not compiled with an "
+ 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");
@@ -1402,6 +1407,7 @@ static int
resolve_ifa_name(struct ifaddrs *ifas, const char *search_ifa, char ***ip_addresses, int *ip_addresses_size)
{
struct ifaddrs *ifa;
+ void *tmpbuf;
int last_ip_addresses_size = *ip_addresses_size;
for(ifa = ifas; ifa != NULL; ifa = ifa->ifa_next) {
@@ -1466,10 +1472,12 @@ resolve_ifa_name(struct ifaddrs *ifas, const char *search_ifa, char ***ip_addres
}
verbose(4, "interface %s has address %s", search_ifa, addr_buf);
- *ip_addresses = realloc(*ip_addresses, sizeof(char *) * (*ip_addresses_size + 1));
- if(!*ip_addresses) {
+ tmpbuf = realloc(*ip_addresses, sizeof(char *) * (*ip_addresses_size + 1));
+ if(!tmpbuf) {
log_err("realloc failed: out of memory");
return 0;
+ } else {
+ *ip_addresses = tmpbuf;
}
(*ip_addresses)[*ip_addresses_size] = strdup(addr_buf);
if(!(*ip_addresses)[*ip_addresses_size]) {
@@ -1480,10 +1488,12 @@ resolve_ifa_name(struct ifaddrs *ifas, const char *search_ifa, char ***ip_addres
}
if (*ip_addresses_size == last_ip_addresses_size) {
- *ip_addresses = realloc(*ip_addresses, sizeof(char *) * (*ip_addresses_size + 1));
- if(!*ip_addresses) {
+ tmpbuf = realloc(*ip_addresses, sizeof(char *) * (*ip_addresses_size + 1));
+ if(!tmpbuf) {
log_err("realloc failed: out of memory");
return 0;
+ } else {
+ *ip_addresses = tmpbuf;
}
(*ip_addresses)[*ip_addresses_size] = strdup(search_ifa);
if(!(*ip_addresses)[*ip_addresses_size]) {
@@ -1804,8 +1814,7 @@ tcp_req_info_setup_listen(struct tcp_req_info* req)
if(!req->cp->tcp_is_reading)
wr = 1;
- if(req->num_open_req + req->num_done_req < TCP_MAX_REQ_SIMULTANEOUS &&
- !req->read_is_closed)
+ if(!req->read_is_closed)
rd = 1;
if(wr) {
@@ -2177,9 +2186,10 @@ int http2_submit_dns_response(struct http2_session* h2_session)
int ret;
nghttp2_data_provider data_prd;
char status[4];
- nghttp2_nv headers[2];
+ nghttp2_nv headers[3];
struct http2_stream* h2_stream = h2_session->c->h2_stream;
size_t rlen;
+ char rlen_str[32];
if(h2_stream->rbuffer) {
log_err("http2 submit response error: rbuffer already "
@@ -2198,6 +2208,8 @@ int http2_submit_dns_response(struct http2_session* h2_session)
}
rlen = sldns_buffer_remaining(h2_session->c->buffer);
+ snprintf(rlen_str, sizeof(rlen_str), "%u", (unsigned)rlen);
+
lock_basic_lock(&http2_response_buffer_count_lock);
if(http2_response_buffer_count + rlen > http2_response_buffer_max) {
lock_basic_unlock(&http2_response_buffer_count_lock);
@@ -2228,13 +2240,11 @@ int http2_submit_dns_response(struct http2_session* h2_session)
headers[1].valuelen = 23;
headers[1].flags = NGHTTP2_NV_FLAG_NONE;
- /*TODO be nice and add the content-length header
headers[2].name = (uint8_t*)"content-length";
headers[2].namelen = 14;
- headers[2].value =
- headers[2].valuelen =
+ headers[2].value = (uint8_t*)rlen_str;
+ headers[2].valuelen = strlen(rlen_str);
headers[2].flags = NGHTTP2_NV_FLAG_NONE;
- */
sldns_buffer_write(h2_stream->rbuffer,
sldns_buffer_current(h2_session->c->buffer),
@@ -2244,7 +2254,7 @@ int http2_submit_dns_response(struct http2_session* h2_session)
data_prd.source.ptr = h2_session;
data_prd.read_callback = http2_submit_response_read_callback;
ret = nghttp2_submit_response(h2_session->session, h2_stream->stream_id,
- headers, 2, &data_prd);
+ headers, 3, &data_prd);
if(ret) {
verbose(VERB_QUERY, "http2: set_stream_user_data failed, "
"error: %s", nghttp2_strerror(ret));
diff --git a/contrib/unbound/services/listen_dnsport.h b/contrib/unbound/services/listen_dnsport.h
index 4bbde0691fec..9d6ea2c33adf 100644
--- a/contrib/unbound/services/listen_dnsport.h
+++ b/contrib/unbound/services/listen_dnsport.h
@@ -159,6 +159,7 @@ int resolve_interface_names(struct config_file* cfg, char*** resif,
* @param harden_large_queries: whether query size should be limited.
* @param http_max_streams: maximum number of HTTP/2 streams per connection.
* @param http_endpoint: HTTP endpoint to service queries on
+ * @param http_notls: no TLS for http downstream
* @param tcp_conn_limit: TCP connection limit info.
* @param sslctx: nonNULL if ssl context.
* @param dtenv: nonNULL if dnstap enabled.
@@ -171,8 +172,9 @@ struct listen_dnsport*
listen_create(struct comm_base* base, struct listen_port* ports,
size_t bufsize, int tcp_accept_count, int tcp_idle_timeout,
int harden_large_queries, uint32_t http_max_streams,
- char* http_endpoint, struct tcl_list* tcp_conn_limit, void* sslctx,
- struct dt_env* dtenv, comm_point_callback_type* cb, void *cb_arg);
+ char* http_endpoint, int http_notls, struct tcl_list* tcp_conn_limit,
+ void* sslctx, struct dt_env* dtenv, comm_point_callback_type* cb,
+ void *cb_arg);
/**
* delete the listening structure
diff --git a/contrib/unbound/services/localzone.c b/contrib/unbound/services/localzone.c
index 6aaf0c05518c..cad46066334c 100644
--- a/contrib/unbound/services/localzone.c
+++ b/contrib/unbound/services/localzone.c
@@ -157,7 +157,7 @@ local_zone_create(uint8_t* nm, size_t len, int labs,
z->namelen = len;
z->namelabs = labs;
lock_rw_init(&z->lock);
- z->region = regional_create_custom(sizeof(struct regional));
+ z->region = regional_create_nochunk(sizeof(struct regional));
if(!z->region) {
free(z);
return NULL;
diff --git a/contrib/unbound/services/mesh.c b/contrib/unbound/services/mesh.c
index 52ff97e4a2e8..cd90509366f2 100644
--- a/contrib/unbound/services/mesh.c
+++ b/contrib/unbound/services/mesh.c
@@ -1196,6 +1196,12 @@ mesh_send_reply(struct mesh_state* m, int rcode, struct reply_info* rep,
/* 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;
/* examine security status */
if(m->s.env->need_to_validate && (!(r->qflags&BIT_CD) ||
m->s.env->cfg->ignore_cd) && rep &&
@@ -1218,15 +1224,21 @@ mesh_send_reply(struct mesh_state* m, int rcode, struct reply_info* rep,
r->h2_stream->mesh_state = NULL;
}
/* send the reply */
- /* We don't reuse the encoded answer if either the previous or current
- * response has a local alias. We could compare the alias records
- * and still reuse the previous answer if they are the same, but that
- * would be complicated and error prone for the relatively minor case.
- * So we err on the side of safety. */
- if(prev && prev_buffer && prev->qflags == r->qflags &&
+ /* We don't reuse the encoded answer if:
+ * - either the previous or current response has a local alias. We could
+ * compare the alias records and still reuse the previous answer if they
+ * are the same, but that would be complicated and error prone for the
+ * relatively minor case. So we err on the side of safety.
+ * - there are registered callback functions for the given rcode, as these
+ * need to be called for each reply. */
+ if(((rcode != LDNS_RCODE_SERVFAIL &&
+ !m->s.env->inplace_cb_lists[inplace_cb_reply]) ||
+ (rcode == LDNS_RCODE_SERVFAIL &&
+ !m->s.env->inplace_cb_lists[inplace_cb_reply_servfail])) &&
+ prev && prev_buffer && prev->qflags == r->qflags &&
!prev->local_alias && !r->local_alias &&
- prev->edns.edns_present == r->edns.edns_present &&
- prev->edns.bits == r->edns.bits &&
+ 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) {
@@ -1236,22 +1248,26 @@ mesh_send_reply(struct mesh_state* m, int rcode, struct reply_info* rep,
sldns_buffer_write_at(r_buffer, 0, &r->qid, sizeof(uint16_t));
sldns_buffer_write_at(r_buffer, 12, r->qname,
m->s.qinfo.qname_len);
+ m->reply_list = NULL;
comm_point_send_reply(&r->query_reply);
+ m->reply_list = rlist;
} else if(rcode) {
m->s.qinfo.qname = r->qname;
m->s.qinfo.local_alias = r->local_alias;
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))
+ rep, rcode, &r->edns, &r->query_reply, m->s.region))
r->edns.opt_list = NULL;
} else {
if(!inplace_cb_reply_call(m->s.env, &m->s.qinfo, &m->s, rep, rcode,
- &r->edns, NULL, m->s.region))
+ &r->edns, &r->query_reply, m->s.region))
r->edns.opt_list = NULL;
}
error_encode(r_buffer, rcode, &m->s.qinfo, r->qid,
r->qflags, &r->edns);
+ m->reply_list = NULL;
comm_point_send_reply(&r->query_reply);
+ m->reply_list = rlist;
} else {
size_t udp_size = r->edns.udp_size;
r->edns.edns_version = EDNS_ADVERTISED_VERSION;
@@ -1261,7 +1277,7 @@ mesh_send_reply(struct mesh_state* m, int rcode, struct reply_info* rep,
m->s.qinfo.qname = r->qname;
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, NULL, m->s.region) ||
+ LDNS_RCODE_NOERROR, &r->edns, &r->query_reply, m->s.region) ||
!apply_edns_options(&r->edns, &edns_bak,
m->s.env->cfg, r->query_reply.c,
m->s.region) ||
@@ -1271,13 +1287,15 @@ mesh_send_reply(struct mesh_state* m, int rcode, struct reply_info* rep,
secure))
{
if(!inplace_cb_reply_servfail_call(m->s.env, &m->s.qinfo, &m->s,
- rep, LDNS_RCODE_SERVFAIL, &r->edns, NULL, m->s.region))
+ rep, LDNS_RCODE_SERVFAIL, &r->edns, &r->query_reply, m->s.region))
r->edns.opt_list = 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;
}
/* account */
log_assert(m->s.env->mesh->num_reply_addrs > 0);
@@ -1365,20 +1383,12 @@ void mesh_query_done(struct mesh_state* mstate)
mstate->reply_list = reply_list;
} else {
struct sldns_buffer* r_buffer = r->query_reply.c->buffer;
- struct mesh_reply* rlist = mstate->reply_list;
if(r->query_reply.c->tcp_req_info) {
r_buffer = r->query_reply.c->tcp_req_info->spool_buffer;
prev_buffer = NULL;
}
- /* 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 */
- mstate->reply_list = NULL;
mesh_send_reply(mstate, mstate->s.return_rcode, rep,
r, r_buffer, prev, prev_buffer);
- mstate->reply_list = rlist;
if(r->query_reply.c->tcp_req_info) {
tcp_req_info_remove_mesh_state(r->query_reply.c->tcp_req_info, mstate);
r_buffer = NULL;
@@ -1894,7 +1904,7 @@ mesh_serve_expired_callback(void* arg)
{
struct mesh_state* mstate = (struct mesh_state*) arg;
struct module_qstate* qstate = &mstate->s;
- struct mesh_reply* r, *rlist;
+ struct mesh_reply* r;
struct mesh_area* mesh = qstate->env->mesh;
struct dns_msg* msg;
struct mesh_cb* c;
@@ -1999,15 +2009,8 @@ mesh_serve_expired_callback(void* arg)
r_buffer = r->query_reply.c->buffer;
if(r->query_reply.c->tcp_req_info)
r_buffer = r->query_reply.c->tcp_req_info->spool_buffer;
- /* 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 */
- rlist = mstate->reply_list;
- mstate->reply_list = NULL;
mesh_send_reply(mstate, LDNS_RCODE_NOERROR, msg->rep,
r, r_buffer, prev, prev_buffer);
- mstate->reply_list = rlist;
if(r->query_reply.c->tcp_req_info)
tcp_req_info_remove_mesh_state(r->query_reply.c->tcp_req_info, mstate);
prev = r;
diff --git a/contrib/unbound/services/outside_network.c b/contrib/unbound/services/outside_network.c
index 41a1d83f1454..11951adea7bc 100644
--- a/contrib/unbound/services/outside_network.c
+++ b/contrib/unbound/services/outside_network.c
@@ -132,6 +132,52 @@ serviced_cmp(const void* key1, const void* key2)
return sockaddr_cmp(&q1->addr, q1->addrlen, &q2->addr, q2->addrlen);
}
+/** compare if the reuse element has the same address, port and same ssl-is
+ * used-for-it characteristic */
+static int
+reuse_cmp_addrportssl(const void* key1, const void* key2)
+{
+ struct reuse_tcp* r1 = (struct reuse_tcp*)key1;
+ struct reuse_tcp* r2 = (struct reuse_tcp*)key2;
+ int r;
+ /* compare address and port */
+ r = sockaddr_cmp(&r1->addr, r1->addrlen, &r2->addr, r2->addrlen);
+ if(r != 0)
+ return r;
+
+ /* compare if SSL-enabled */
+ if(r1->is_ssl && !r2->is_ssl)
+ return 1;
+ if(!r1->is_ssl && r2->is_ssl)
+ return -1;
+ return 0;
+}
+
+int
+reuse_cmp(const void* key1, const void* key2)
+{
+ int r;
+ r = reuse_cmp_addrportssl(key1, key2);
+ if(r != 0)
+ return r;
+
+ /* compare ptr value */
+ if(key1 < key2) return -1;
+ if(key1 > key2) return 1;
+ return 0;
+}
+
+int reuse_id_cmp(const void* key1, const void* key2)
+{
+ struct waiting_tcp* w1 = (struct waiting_tcp*)key1;
+ struct waiting_tcp* w2 = (struct waiting_tcp*)key2;
+ if(w1->id < w2->id)
+ return -1;
+ if(w1->id > w2->id)
+ return 1;
+ return 0;
+}
+
/** delete waiting_tcp entry. Does not unlink from waiting list.
* @param w: to delete.
*/
@@ -280,15 +326,234 @@ outnet_tcp_connect(int s, struct sockaddr_storage* addr, socklen_t addrlen)
return 1;
}
+/** log reuse item addr and ptr with message */
+static void
+log_reuse_tcp(enum verbosity_value v, const char* msg, struct reuse_tcp* reuse)
+{
+ uint16_t port;
+ char addrbuf[128];
+ if(verbosity < v) return;
+ addr_to_str(&reuse->addr, reuse->addrlen, addrbuf, sizeof(addrbuf));
+ port = ntohs(((struct sockaddr_in*)&reuse->addr)->sin_port);
+ verbose(v, "%s %s#%u fd %d", msg, addrbuf, (unsigned)port,
+ reuse->pending->c->fd);
+}
+
+/** pop the first element from the writewait list */
+static struct waiting_tcp* reuse_write_wait_pop(struct reuse_tcp* reuse)
+{
+ struct waiting_tcp* w = reuse->write_wait_first;
+ if(!w)
+ return NULL;
+ log_assert(w->write_wait_queued);
+ log_assert(!w->write_wait_prev);
+ reuse->write_wait_first = w->write_wait_next;
+ if(w->write_wait_next)
+ w->write_wait_next->write_wait_prev = NULL;
+ else reuse->write_wait_last = NULL;
+ w->write_wait_queued = 0;
+ return w;
+}
+
+/** remove the element from the writewait list */
+static void reuse_write_wait_remove(struct reuse_tcp* reuse,
+ struct waiting_tcp* w)
+{
+ if(!w)
+ return;
+ if(!w->write_wait_queued)
+ return;
+ if(w->write_wait_prev)
+ w->write_wait_prev->write_wait_next = w->write_wait_next;
+ else reuse->write_wait_first = w->write_wait_next;
+ if(w->write_wait_next)
+ w->write_wait_next->write_wait_prev = w->write_wait_prev;
+ else reuse->write_wait_last = w->write_wait_prev;
+ w->write_wait_queued = 0;
+}
+
+/** push the element after the last on the writewait list */
+static void reuse_write_wait_push_back(struct reuse_tcp* reuse,
+ struct waiting_tcp* w)
+{
+ if(!w) return;
+ log_assert(!w->write_wait_queued);
+ if(reuse->write_wait_last) {
+ reuse->write_wait_last->write_wait_next = w;
+ w->write_wait_prev = reuse->write_wait_last;
+ } else {
+ reuse->write_wait_first = w;
+ }
+ reuse->write_wait_last = w;
+ w->write_wait_queued = 1;
+}
+
+/** insert element in tree by id */
+void
+reuse_tree_by_id_insert(struct reuse_tcp* reuse, struct waiting_tcp* w)
+{
+ log_assert(w->id_node.key == NULL);
+ w->id_node.key = w;
+ rbtree_insert(&reuse->tree_by_id, &w->id_node);
+}
+
+/** find element in tree by id */
+struct waiting_tcp*
+reuse_tcp_by_id_find(struct reuse_tcp* reuse, uint16_t id)
+{
+ struct waiting_tcp key_w;
+ rbnode_type* n;
+ memset(&key_w, 0, sizeof(key_w));
+ key_w.id_node.key = &key_w;
+ key_w.id = id;
+ n = rbtree_search(&reuse->tree_by_id, &key_w);
+ if(!n) return NULL;
+ return (struct waiting_tcp*)n->key;
+}
+
+/** return ID value of rbnode in tree_by_id */
+static uint16_t
+tree_by_id_get_id(rbnode_type* node)
+{
+ struct waiting_tcp* w = (struct waiting_tcp*)node->key;
+ return w->id;
+}
+
+/** insert into reuse tcp tree and LRU, false on failure (duplicate) */
+static int
+reuse_tcp_insert(struct outside_network* outnet, struct pending_tcp* pend_tcp)
+{
+ log_reuse_tcp(VERB_CLIENT, "reuse_tcp_insert", &pend_tcp->reuse);
+ if(pend_tcp->reuse.item_on_lru_list)
+ return 1;
+ pend_tcp->reuse.node.key = &pend_tcp->reuse;
+ pend_tcp->reuse.pending = pend_tcp;
+ if(!rbtree_insert(&outnet->tcp_reuse, &pend_tcp->reuse.node)) {
+ /* this is a duplicate connection, close this one */
+ verbose(VERB_CLIENT, "reuse_tcp_insert: duplicate connection");
+ pend_tcp->reuse.node.key = NULL;
+ return 0;
+ }
+ /* insert into LRU, first is newest */
+ pend_tcp->reuse.lru_prev = NULL;
+ if(outnet->tcp_reuse_first) {
+ pend_tcp->reuse.lru_next = outnet->tcp_reuse_first;
+ outnet->tcp_reuse_first->lru_prev = &pend_tcp->reuse;
+ } else {
+ pend_tcp->reuse.lru_next = NULL;
+ outnet->tcp_reuse_last = &pend_tcp->reuse;
+ }
+ outnet->tcp_reuse_first = &pend_tcp->reuse;
+ pend_tcp->reuse.item_on_lru_list = 1;
+ return 1;
+}
+
+/** find reuse tcp stream to destination for query, or NULL if none */
+static struct reuse_tcp*
+reuse_tcp_find(struct outside_network* outnet, struct sockaddr_storage* addr,
+ socklen_t addrlen, int use_ssl)
+{
+ struct waiting_tcp key_w;
+ struct pending_tcp key_p;
+ struct comm_point c;
+ rbnode_type* result = NULL, *prev;
+ verbose(VERB_CLIENT, "reuse_tcp_find");
+ memset(&key_w, 0, sizeof(key_w));
+ memset(&key_p, 0, sizeof(key_p));
+ memset(&c, 0, sizeof(c));
+ key_p.query = &key_w;
+ key_p.c = &c;
+ key_p.reuse.pending = &key_p;
+ key_p.reuse.node.key = &key_p.reuse;
+ if(use_ssl)
+ key_p.reuse.is_ssl = 1;
+ if(addrlen > (socklen_t)sizeof(key_p.reuse.addr))
+ return NULL;
+ memmove(&key_p.reuse.addr, addr, addrlen);
+ key_p.reuse.addrlen = addrlen;
+
+ verbose(VERB_CLIENT, "reuse_tcp_find: num reuse streams %u",
+ (unsigned)outnet->tcp_reuse.count);
+ if(outnet->tcp_reuse.root == NULL ||
+ outnet->tcp_reuse.root == RBTREE_NULL)
+ return NULL;
+ if(rbtree_find_less_equal(&outnet->tcp_reuse, &key_p.reuse.node,
+ &result)) {
+ /* exact match */
+ /* but the key is on stack, and ptr is compared, impossible */
+ log_assert(&key_p.reuse != (struct reuse_tcp*)result);
+ log_assert(&key_p != ((struct reuse_tcp*)result)->pending);
+ }
+ /* not found, return null */
+ if(!result || result == RBTREE_NULL)
+ return NULL;
+ verbose(VERB_CLIENT, "reuse_tcp_find check inexact match");
+ /* inexact match, find one of possibly several connections to the
+ * same destination address, with the correct port, ssl, and
+ * also less than max number of open queries, or else, fail to open
+ * a new one */
+ /* rewind to start of sequence of same address,port,ssl */
+ prev = rbtree_previous(result);
+ while(prev && prev != RBTREE_NULL &&
+ reuse_cmp_addrportssl(prev->key, &key_p.reuse) == 0) {
+ result = prev;
+ prev = rbtree_previous(result);
+ }
+
+ /* loop to find first one that has correct characteristics */
+ while(result && result != RBTREE_NULL &&
+ reuse_cmp_addrportssl(result->key, &key_p.reuse) == 0) {
+ if(((struct reuse_tcp*)result)->tree_by_id.count <
+ MAX_REUSE_TCP_QUERIES) {
+ /* same address, port, ssl-yes-or-no, and has
+ * space for another query */
+ return (struct reuse_tcp*)result;
+ }
+ result = rbtree_next(result);
+ }
+ return NULL;
+}
+
+/** use the buffer to setup writing the query */
+static void
+outnet_tcp_take_query_setup(int s, struct pending_tcp* pend,
+ struct waiting_tcp* w)
+{
+ struct timeval tv;
+ verbose(VERB_CLIENT, "outnet_tcp_take_query_setup: setup packet to write "
+ "len %d timeout %d msec",
+ (int)w->pkt_len, w->timeout);
+ pend->c->tcp_write_pkt = w->pkt;
+ pend->c->tcp_write_pkt_len = w->pkt_len;
+ pend->c->tcp_write_and_read = 1;
+ pend->c->tcp_write_byte_count = 0;
+ pend->c->tcp_is_reading = 0;
+ comm_point_start_listening(pend->c, s, -1);
+ /* set timer on the waiting_tcp entry, this is the write timeout
+ * for the written packet. The timer on pend->c is the timer
+ * for when there is no written packet and we have readtimeouts */
+#ifndef S_SPLINT_S
+ tv.tv_sec = w->timeout/1000;
+ tv.tv_usec = (w->timeout%1000)*1000;
+#endif
+ /* if the waiting_tcp was previously waiting for a buffer in the
+ * outside_network.tcpwaitlist, then the timer is reset now that
+ * we start writing it */
+ comm_timer_set(w->timer, &tv);
+}
+
/** use next free buffer to service a tcp query */
static int
-outnet_tcp_take_into_use(struct waiting_tcp* w, uint8_t* pkt, size_t pkt_len)
+outnet_tcp_take_into_use(struct waiting_tcp* w)
{
struct pending_tcp* pend = w->outnet->tcp_free;
int s;
log_assert(pend);
- log_assert(pkt);
+ log_assert(w->pkt);
+ log_assert(w->pkt_len > 0);
log_assert(w->addrlen > 0);
+ pend->c->tcp_do_toggle_rw = 0;
+ pend->c->tcp_do_close = 0;
/* open socket */
s = outnet_get_tcp_fd(&w->addr, w->addrlen, w->outnet->tcp_mss, w->outnet->ip_dscp);
@@ -383,24 +648,65 @@ outnet_tcp_take_into_use(struct waiting_tcp* w, uint8_t* pkt, size_t pkt_len)
return 0;
}
}
- w->pkt = NULL;
w->next_waiting = (void*)pend;
- pend->id = LDNS_ID_WIRE(pkt);
w->outnet->num_tcp_outgoing++;
w->outnet->tcp_free = pend->next_free;
pend->next_free = NULL;
pend->query = w;
+ pend->reuse.outnet = w->outnet;
pend->c->repinfo.addrlen = w->addrlen;
+ pend->c->tcp_more_read_again = &pend->reuse.cp_more_read_again;
+ pend->c->tcp_more_write_again = &pend->reuse.cp_more_write_again;
+ pend->reuse.cp_more_read_again = 0;
+ pend->reuse.cp_more_write_again = 0;
memcpy(&pend->c->repinfo.addr, &w->addr, w->addrlen);
- sldns_buffer_clear(pend->c->buffer);
- sldns_buffer_write(pend->c->buffer, pkt, pkt_len);
- sldns_buffer_flip(pend->c->buffer);
- pend->c->tcp_is_reading = 0;
- pend->c->tcp_byte_count = 0;
- comm_point_start_listening(pend->c, s, -1);
+ pend->reuse.pending = pend;
+ if(pend->c->ssl)
+ pend->reuse.is_ssl = 1;
+ else pend->reuse.is_ssl = 0;
+ /* insert in reuse by address tree if not already inserted there */
+ (void)reuse_tcp_insert(w->outnet, pend);
+ reuse_tree_by_id_insert(&pend->reuse, w);
+ outnet_tcp_take_query_setup(s, pend, w);
return 1;
}
+/** Touch the lru of a reuse_tcp element, it is in use.
+ * This moves it to the front of the list, where it is not likely to
+ * be closed. Items at the back of the list are closed to make space. */
+static void
+reuse_tcp_lru_touch(struct outside_network* outnet, struct reuse_tcp* reuse)
+{
+ if(!reuse->item_on_lru_list)
+ return; /* not on the list, no lru to modify */
+ if(!reuse->lru_prev)
+ return; /* already first in the list */
+ /* remove at current position */
+ /* since it is not first, there is a previous element */
+ reuse->lru_prev->lru_next = reuse->lru_next;
+ if(reuse->lru_next)
+ reuse->lru_next->lru_prev = reuse->lru_prev;
+ else outnet->tcp_reuse_last = reuse->lru_prev;
+ /* insert at the front */
+ reuse->lru_prev = NULL;
+ reuse->lru_next = outnet->tcp_reuse_first;
+ /* since it is not first, it is not the only element and
+ * lru_next is thus not NULL and thus reuse is now not the last in
+ * the list, so outnet->tcp_reuse_last does not need to be modified */
+ outnet->tcp_reuse_first = reuse;
+}
+
+/** call callback on waiting_tcp, if not NULL */
+static void
+waiting_tcp_callback(struct waiting_tcp* w, struct comm_point* c, int error,
+ struct comm_reply* reply_info)
+{
+ if(w->cb) {
+ fptr_ok(fptr_whitelist_pending_tcp(w->cb));
+ (void)(*w->cb)(c, w->cb_arg, error, reply_info);
+ }
+}
+
/** see if buffers can be used to service TCP queries */
static void
use_free_buffer(struct outside_network* outnet)
@@ -408,25 +714,198 @@ use_free_buffer(struct outside_network* outnet)
struct waiting_tcp* w;
while(outnet->tcp_free && outnet->tcp_wait_first
&& !outnet->want_to_quit) {
+ struct reuse_tcp* reuse = NULL;
w = outnet->tcp_wait_first;
outnet->tcp_wait_first = w->next_waiting;
if(outnet->tcp_wait_last == w)
outnet->tcp_wait_last = NULL;
- if(!outnet_tcp_take_into_use(w, w->pkt, w->pkt_len)) {
- comm_point_callback_type* cb = w->cb;
- void* cb_arg = w->cb_arg;
- waiting_tcp_delete(w);
- fptr_ok(fptr_whitelist_pending_tcp(cb));
- (void)(*cb)(NULL, cb_arg, NETEVENT_CLOSED, NULL);
+ w->on_tcp_waiting_list = 0;
+ reuse = reuse_tcp_find(outnet, &w->addr, w->addrlen,
+ w->ssl_upstream);
+ if(reuse) {
+ log_reuse_tcp(VERB_CLIENT, "use free buffer for waiting tcp: "
+ "found reuse", reuse);
+ reuse_tcp_lru_touch(outnet, reuse);
+ comm_timer_disable(w->timer);
+ w->next_waiting = (void*)reuse->pending;
+ reuse_tree_by_id_insert(reuse, w);
+ if(reuse->pending->query) {
+ /* on the write wait list */
+ reuse_write_wait_push_back(reuse, w);
+ } else {
+ /* write straight away */
+ /* stop the timer on read of the fd */
+ comm_point_stop_listening(reuse->pending->c);
+ reuse->pending->query = w;
+ outnet_tcp_take_query_setup(
+ reuse->pending->c->fd, reuse->pending,
+ w);
+ }
+ } else {
+ struct pending_tcp* pend = w->outnet->tcp_free;
+ rbtree_init(&pend->reuse.tree_by_id, reuse_id_cmp);
+ pend->reuse.pending = pend;
+ memcpy(&pend->reuse.addr, &w->addr, w->addrlen);
+ pend->reuse.addrlen = w->addrlen;
+ if(!outnet_tcp_take_into_use(w)) {
+ waiting_tcp_callback(w, NULL, NETEVENT_CLOSED,
+ NULL);
+ waiting_tcp_delete(w);
+ }
}
}
}
+/** add waiting_tcp element to the outnet tcp waiting list */
+static void
+outnet_add_tcp_waiting(struct outside_network* outnet, struct waiting_tcp* w)
+{
+ struct timeval tv;
+ if(w->on_tcp_waiting_list)
+ return;
+ w->next_waiting = NULL;
+ if(outnet->tcp_wait_last)
+ outnet->tcp_wait_last->next_waiting = w;
+ else outnet->tcp_wait_first = w;
+ outnet->tcp_wait_last = w;
+ w->on_tcp_waiting_list = 1;
+#ifndef S_SPLINT_S
+ tv.tv_sec = w->timeout/1000;
+ tv.tv_usec = (w->timeout%1000)*1000;
+#endif
+ comm_timer_set(w->timer, &tv);
+}
+
+/** delete element from tree by id */
+static void
+reuse_tree_by_id_delete(struct reuse_tcp* reuse, struct waiting_tcp* w)
+{
+ log_assert(w->id_node.key != NULL);
+ rbtree_delete(&reuse->tree_by_id, w);
+ w->id_node.key = NULL;
+}
+
+/** move writewait list to go for another connection. */
+static void
+reuse_move_writewait_away(struct outside_network* outnet,
+ struct pending_tcp* pend)
+{
+ /* the writewait list has not been written yet, so if the
+ * stream was closed, they have not actually been failed, only
+ * the queries written. Other queries can get written to another
+ * stream. For upstreams that do not support multiple queries
+ * and answers, the stream can get closed, and then the queries
+ * can get written on a new socket */
+ struct waiting_tcp* w;
+ if(pend->query && pend->query->error_count == 0 &&
+ pend->c->tcp_write_pkt == pend->query->pkt &&
+ pend->c->tcp_write_pkt_len == pend->query->pkt_len) {
+ /* since the current query is not written, it can also
+ * move to a free buffer */
+ if(verbosity >= VERB_CLIENT && pend->query->pkt_len > 12+2+2 &&
+ LDNS_QDCOUNT(pend->query->pkt) > 0 &&
+ dname_valid(pend->query->pkt+12, pend->query->pkt_len-12)) {
+ char buf[LDNS_MAX_DOMAINLEN+1];
+ dname_str(pend->query->pkt+12, buf);
+ verbose(VERB_CLIENT, "reuse_move_writewait_away current %s %d bytes were written",
+ buf, (int)pend->c->tcp_write_byte_count);
+ }
+ pend->c->tcp_write_pkt = NULL;
+ pend->c->tcp_write_pkt_len = 0;
+ pend->c->tcp_write_and_read = 0;
+ pend->reuse.cp_more_read_again = 0;
+ pend->reuse.cp_more_write_again = 0;
+ pend->c->tcp_is_reading = 1;
+ w = pend->query;
+ pend->query = NULL;
+ /* increase error count, so that if the next socket fails too
+ * the server selection is run again with this query failed
+ * and it can select a different server (if possible), or
+ * fail the query */
+ w->error_count ++;
+ reuse_tree_by_id_delete(&pend->reuse, w);
+ outnet_add_tcp_waiting(outnet, w);
+ }
+ while((w = reuse_write_wait_pop(&pend->reuse)) != NULL) {
+ if(verbosity >= VERB_CLIENT && w->pkt_len > 12+2+2 &&
+ LDNS_QDCOUNT(w->pkt) > 0 &&
+ dname_valid(w->pkt+12, w->pkt_len-12)) {
+ char buf[LDNS_MAX_DOMAINLEN+1];
+ dname_str(w->pkt+12, buf);
+ verbose(VERB_CLIENT, "reuse_move_writewait_away item %s", buf);
+ }
+ reuse_tree_by_id_delete(&pend->reuse, w);
+ outnet_add_tcp_waiting(outnet, w);
+ }
+}
+
+/** remove reused element from tree and lru list */
+static void
+reuse_tcp_remove_tree_list(struct outside_network* outnet,
+ struct reuse_tcp* reuse)
+{
+ verbose(VERB_CLIENT, "reuse_tcp_remove_tree_list");
+ if(reuse->node.key) {
+ /* delete it from reuse tree */
+ (void)rbtree_delete(&outnet->tcp_reuse, &reuse->node);
+ reuse->node.key = NULL;
+ }
+ /* delete from reuse list */
+ if(reuse->item_on_lru_list) {
+ if(reuse->lru_prev) {
+ /* assert that members of the lru list are waiting
+ * and thus have a pending pointer to the struct */
+ log_assert(reuse->lru_prev->pending);
+ reuse->lru_prev->lru_next = reuse->lru_next;
+ } else {
+ log_assert(!reuse->lru_next || reuse->lru_next->pending);
+ outnet->tcp_reuse_first = reuse->lru_next;
+ }
+ if(reuse->lru_next) {
+ /* assert that members of the lru list are waiting
+ * and thus have a pending pointer to the struct */
+ log_assert(reuse->lru_next->pending);
+ reuse->lru_next->lru_prev = reuse->lru_prev;
+ } else {
+ log_assert(!reuse->lru_prev || reuse->lru_prev->pending);
+ outnet->tcp_reuse_last = reuse->lru_prev;
+ }
+ reuse->item_on_lru_list = 0;
+ }
+}
+
+/** helper function that deletes an element from the tree of readwait
+ * elements in tcp reuse structure */
+static void reuse_del_readwait_elem(rbnode_type* node, void* ATTR_UNUSED(arg))
+{
+ struct waiting_tcp* w = (struct waiting_tcp*)node->key;
+ waiting_tcp_delete(w);
+}
+
+/** delete readwait waiting_tcp elements, deletes the elements in the list */
+void reuse_del_readwait(rbtree_type* tree_by_id)
+{
+ if(tree_by_id->root == NULL ||
+ tree_by_id->root == RBTREE_NULL)
+ return;
+ traverse_postorder(tree_by_id, &reuse_del_readwait_elem, NULL);
+ rbtree_init(tree_by_id, reuse_id_cmp);
+}
+
/** decommission a tcp buffer, closes commpoint and frees waiting_tcp entry */
static void
decommission_pending_tcp(struct outside_network* outnet,
struct pending_tcp* pend)
{
+ verbose(VERB_CLIENT, "decommission_pending_tcp");
+ pend->next_free = outnet->tcp_free;
+ outnet->tcp_free = pend;
+ if(pend->reuse.node.key) {
+ /* needs unlink from the reuse tree to get deleted */
+ reuse_tcp_remove_tree_list(outnet, &pend->reuse);
+ }
+ /* free SSL structure after remove from outnet tcp reuse tree,
+ * because the c->ssl null or not is used for sorting in the tree */
if(pend->c->ssl) {
#ifdef HAVE_SSL
SSL_shutdown(pend->c->ssl);
@@ -435,11 +914,68 @@ decommission_pending_tcp(struct outside_network* outnet,
#endif
}
comm_point_close(pend->c);
- pend->next_free = outnet->tcp_free;
- outnet->tcp_free = pend;
- waiting_tcp_delete(pend->query);
+ pend->reuse.cp_more_read_again = 0;
+ pend->reuse.cp_more_write_again = 0;
+ /* unlink the query and writewait list, it is part of the tree
+ * nodes and is deleted */
pend->query = NULL;
- use_free_buffer(outnet);
+ pend->reuse.write_wait_first = NULL;
+ pend->reuse.write_wait_last = NULL;
+ reuse_del_readwait(&pend->reuse.tree_by_id);
+}
+
+/** perform failure callbacks for waiting queries in reuse read rbtree */
+static void reuse_cb_readwait_for_failure(rbtree_type* tree_by_id, int err)
+{
+ rbnode_type* node;
+ if(tree_by_id->root == NULL ||
+ tree_by_id->root == RBTREE_NULL)
+ return;
+ node = rbtree_first(tree_by_id);
+ while(node && node != RBTREE_NULL) {
+ struct waiting_tcp* w = (struct waiting_tcp*)node->key;
+ waiting_tcp_callback(w, NULL, err, NULL);
+ node = rbtree_next(node);
+ }
+}
+
+/** 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
+ * removed before the callbacks, so that the callbacks do not modify
+ * the pending_tcp due to its reference in the outside_network reuse tree */
+static void reuse_cb_and_decommission(struct outside_network* outnet,
+ struct pending_tcp* pend, int error)
+{
+ rbtree_type store;
+ store = pend->reuse.tree_by_id;
+ pend->query = NULL;
+ rbtree_init(&pend->reuse.tree_by_id, reuse_id_cmp);
+ pend->reuse.write_wait_first = NULL;
+ pend->reuse.write_wait_last = NULL;
+ decommission_pending_tcp(outnet, pend);
+ reuse_cb_readwait_for_failure(&store, error);
+ reuse_del_readwait(&store);
+}
+
+/** set timeout on tcp fd and setup read event to catch incoming dns msgs */
+static void
+reuse_tcp_setup_timeout(struct pending_tcp* pend_tcp)
+{
+ log_reuse_tcp(VERB_CLIENT, "reuse_tcp_setup_timeout", &pend_tcp->reuse);
+ comm_point_start_listening(pend_tcp->c, -1, REUSE_TIMEOUT);
+}
+
+/** set timeout on tcp fd and setup read event to catch incoming dns msgs */
+static void
+reuse_tcp_setup_read_and_timeout(struct pending_tcp* pend_tcp)
+{
+ log_reuse_tcp(VERB_CLIENT, "reuse_tcp_setup_readtimeout", &pend_tcp->reuse);
+ sldns_buffer_clear(pend_tcp->c->buffer);
+ pend_tcp->c->tcp_is_reading = 1;
+ pend_tcp->c->tcp_byte_count = 0;
+ comm_point_stop_listening(pend_tcp->c);
+ comm_point_start_listening(pend_tcp->c, -1, REUSE_TIMEOUT);
}
int
@@ -447,24 +983,116 @@ outnet_tcp_cb(struct comm_point* c, void* arg, int error,
struct comm_reply *reply_info)
{
struct pending_tcp* pend = (struct pending_tcp*)arg;
- struct outside_network* outnet = pend->query->outnet;
+ struct outside_network* outnet = pend->reuse.outnet;
+ struct waiting_tcp* w = NULL;
verbose(VERB_ALGO, "outnettcp cb");
- if(error != NETEVENT_NOERROR) {
+ if(error == NETEVENT_TIMEOUT) {
+ if(pend->c->tcp_write_and_read) {
+ verbose(VERB_QUERY, "outnettcp got tcp timeout "
+ "for read, ignored because write underway");
+ /* if we are writing, ignore readtimer, wait for write timer
+ * or write is done */
+ return 0;
+ } else {
+ verbose(VERB_QUERY, "outnettcp got tcp timeout %s",
+ (pend->reuse.tree_by_id.count?"for reading pkt":
+ "for keepalive for reuse"));
+ }
+ /* must be timeout for reading or keepalive reuse,
+ * close it. */
+ reuse_tcp_remove_tree_list(outnet, &pend->reuse);
+ } else if(error == NETEVENT_PKT_WRITTEN) {
+ /* the packet we want to write has been written. */
+ verbose(VERB_ALGO, "outnet tcp pkt was written event");
+ log_assert(c == pend->c);
+ log_assert(pend->query->pkt == pend->c->tcp_write_pkt);
+ log_assert(pend->query->pkt_len == pend->c->tcp_write_pkt_len);
+ pend->c->tcp_write_pkt = NULL;
+ pend->c->tcp_write_pkt_len = 0;
+ /* the pend.query is already in tree_by_id */
+ log_assert(pend->query->id_node.key);
+ pend->query = NULL;
+ /* setup to write next packet or setup read timeout */
+ if(pend->reuse.write_wait_first) {
+ verbose(VERB_ALGO, "outnet tcp setup next pkt");
+ /* we can write it straight away perhaps, set flag
+ * because this callback called after a tcp write
+ * succeeded and likely more buffer space is available
+ * and we can write some more. */
+ pend->reuse.cp_more_write_again = 1;
+ pend->query = reuse_write_wait_pop(&pend->reuse);
+ comm_point_stop_listening(pend->c);
+ outnet_tcp_take_query_setup(pend->c->fd, pend,
+ pend->query);
+ } else {
+ verbose(VERB_ALGO, "outnet tcp writes done, wait");
+ pend->c->tcp_write_and_read = 0;
+ pend->reuse.cp_more_read_again = 0;
+ pend->reuse.cp_more_write_again = 0;
+ pend->c->tcp_is_reading = 1;
+ comm_point_stop_listening(pend->c);
+ reuse_tcp_setup_timeout(pend);
+ }
+ return 0;
+ } else if(error != NETEVENT_NOERROR) {
verbose(VERB_QUERY, "outnettcp got tcp error %d", error);
+ reuse_move_writewait_away(outnet, pend);
/* pass error below and exit */
} else {
/* check ID */
- if(sldns_buffer_limit(c->buffer) < sizeof(uint16_t) ||
- LDNS_ID_WIRE(sldns_buffer_begin(c->buffer))!=pend->id) {
+ if(sldns_buffer_limit(c->buffer) < sizeof(uint16_t)) {
log_addr(VERB_QUERY,
- "outnettcp: bad ID in reply, from:",
- &pend->query->addr, pend->query->addrlen);
+ "outnettcp: bad ID in reply, too short, from:",
+ &pend->reuse.addr, pend->reuse.addrlen);
error = NETEVENT_CLOSED;
- }
+ } else {
+ uint16_t id = LDNS_ID_WIRE(sldns_buffer_begin(
+ c->buffer));
+ /* find the query the reply is for */
+ w = reuse_tcp_by_id_find(&pend->reuse, id);
+ }
+ }
+ if(error == NETEVENT_NOERROR && !w) {
+ /* no struct waiting found in tree, no reply to call */
+ log_addr(VERB_QUERY, "outnettcp: bad ID in reply, from:",
+ &pend->reuse.addr, pend->reuse.addrlen);
+ error = NETEVENT_CLOSED;
+ }
+ if(error == NETEVENT_NOERROR) {
+ /* add to reuse tree so it can be reused, if not a failure.
+ * This is possible if the state machine wants to make a tcp
+ * query again to the same destination. */
+ if(outnet->tcp_reuse.count < outnet->tcp_reuse_max) {
+ (void)reuse_tcp_insert(outnet, pend);
+ }
+ }
+ if(w) {
+ 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));
+ waiting_tcp_callback(w, c, error, reply_info);
+ waiting_tcp_delete(w);
+ }
+ verbose(VERB_CLIENT, "outnet_tcp_cb reuse after cb");
+ if(error == NETEVENT_NOERROR && pend->reuse.node.key) {
+ verbose(VERB_CLIENT, "outnet_tcp_cb reuse after cb: keep it");
+ /* it is in the reuse_tcp tree, with other queries, or
+ * on the empty list. do not decommission it */
+ /* if there are more outstanding queries, we could try to
+ * read again, to see if it is on the input,
+ * because this callback called after a successful read
+ * and there could be more bytes to read on the input */
+ if(pend->reuse.tree_by_id.count != 0)
+ pend->reuse.cp_more_read_again = 1;
+ reuse_tcp_setup_read_and_timeout(pend);
+ return 0;
}
- fptr_ok(fptr_whitelist_pending_tcp(pend->query->cb));
- (void)(*pend->query->cb)(c, pend->query->cb_arg, error, reply_info);
- decommission_pending_tcp(outnet, pend);
+ verbose(VERB_CLIENT, "outnet_tcp_cb reuse after cb: decommission it");
+ /* no queries on it, no space to keep it. or timeout or closed due
+ * to error. Close it */
+ reuse_cb_and_decommission(outnet, pend, (error==NETEVENT_TIMEOUT?
+ NETEVENT_TIMEOUT:NETEVENT_CLOSED));
+ use_free_buffer(outnet);
return 0;
}
@@ -723,7 +1351,8 @@ outside_network_create(struct comm_base *base, size_t bufsize,
struct ub_randstate* rnd, int use_caps_for_id, int* availports,
int numavailports, size_t unwanted_threshold, int tcp_mss,
void (*unwanted_action)(void*), void* unwanted_param, int do_udp,
- void* sslctx, int delayclose, int tls_use_sni, struct dt_env* dtenv)
+ void* sslctx, int delayclose, int tls_use_sni, struct dt_env* dtenv,
+ int udp_connect)
{
struct outside_network* outnet = (struct outside_network*)
calloc(1, sizeof(struct outside_network));
@@ -761,6 +1390,9 @@ outside_network_create(struct comm_base *base, size_t bufsize,
outnet->delay_tv.tv_usec = (delayclose%1000)*1000;
}
#endif
+ if(udp_connect) {
+ outnet->udp_connect = 1;
+ }
if(numavailports == 0 || num_ports == 0) {
log_err("no outgoing ports available");
outside_network_delete(outnet);
@@ -795,6 +1427,8 @@ outside_network_create(struct comm_base *base, size_t bufsize,
outside_network_delete(outnet);
return NULL;
}
+ rbtree_init(&outnet->tcp_reuse, reuse_cmp);
+ outnet->tcp_reuse_max = num_tcp;
/* allocate commpoints */
for(k=0; k<num_ports; k++) {
@@ -958,6 +1592,17 @@ outside_network_delete(struct outside_network* outnet)
size_t i;
for(i=0; i<outnet->num_tcp; i++)
if(outnet->tcp_conns[i]) {
+ if(outnet->tcp_conns[i]->query &&
+ !outnet->tcp_conns[i]->query->
+ on_tcp_waiting_list) {
+ /* delete waiting_tcp elements that
+ * the tcp conn is working on */
+ struct pending_tcp* pend =
+ (struct pending_tcp*)outnet->
+ tcp_conns[i]->query->
+ next_waiting;
+ decommission_pending_tcp(outnet, pend);
+ }
comm_point_delete(outnet->tcp_conns[i]->c);
waiting_tcp_delete(outnet->tcp_conns[i]->query);
free(outnet->tcp_conns[i]);
@@ -972,6 +1617,10 @@ outside_network_delete(struct outside_network* outnet)
p = np;
}
}
+ /* was allocated in struct pending that was deleted above */
+ rbtree_init(&outnet->tcp_reuse, reuse_cmp);
+ outnet->tcp_reuse_first = NULL;
+ outnet->tcp_reuse_last = NULL;
if(outnet->udp_wait_first) {
struct pending* p = outnet->udp_wait_first, *np;
while(p) {
@@ -1115,13 +1764,26 @@ select_ifport(struct outside_network* outnet, struct pending* pend,
my_if = ub_random_max(outnet->rnd, num_if);
pif = &ifs[my_if];
#ifndef DISABLE_EXPLICIT_PORT_RANDOMISATION
- my_port = ub_random_max(outnet->rnd, pif->avail_total);
- if(my_port < pif->inuse) {
- /* port already open */
- pend->pc = pif->out[my_port];
- verbose(VERB_ALGO, "using UDP if=%d port=%d",
- my_if, pend->pc->number);
- break;
+ if(outnet->udp_connect) {
+ /* if we connect() we cannot reuse fds for a port */
+ if(pif->inuse >= pif->avail_total) {
+ tries++;
+ if(tries < MAX_PORT_RETRY)
+ continue;
+ log_err("failed to find an open port, drop msg");
+ return 0;
+ }
+ my_port = pif->inuse + ub_random_max(outnet->rnd,
+ pif->avail_total - pif->inuse);
+ } else {
+ my_port = ub_random_max(outnet->rnd, pif->avail_total);
+ if(my_port < pif->inuse) {
+ /* port already open */
+ pend->pc = pif->out[my_port];
+ verbose(VERB_ALGO, "using UDP if=%d port=%d",
+ my_if, pend->pc->number);
+ break;
+ }
}
/* try to open new port, if fails, loop to try again */
log_assert(pif->inuse < pif->maxout);
@@ -1138,6 +1800,17 @@ select_ifport(struct outside_network* outnet, struct pending* pend,
if(fd != -1) {
verbose(VERB_ALGO, "opened UDP if=%d port=%d",
my_if, portno);
+ if(outnet->udp_connect) {
+ /* connect() to the destination */
+ if(connect(fd, (struct sockaddr*)&pend->addr,
+ pend->addrlen) < 0) {
+ log_err_addr("udp connect failed",
+ strerror(errno), &pend->addr,
+ pend->addrlen);
+ sock_close(fd);
+ return 0;
+ }
+ }
/* grab fd */
pend->pc = outnet->unused_fds;
outnet->unused_fds = pend->pc->next;
@@ -1197,10 +1870,17 @@ randomize_and_send_udp(struct pending* pend, sldns_buffer* packet, int timeout)
log_assert(pend->pc && pend->pc->cp);
/* send it over the commlink */
- if(!comm_point_send_udp_msg(pend->pc->cp, packet,
- (struct sockaddr*)&pend->addr, pend->addrlen)) {
- portcomm_loweruse(outnet, pend->pc);
- return 0;
+ if(outnet->udp_connect) {
+ if(!comm_point_send_udp_msg(pend->pc->cp, packet, NULL, 0)) {
+ portcomm_loweruse(outnet, pend->pc);
+ return 0;
+ }
+ } else {
+ if(!comm_point_send_udp_msg(pend->pc->cp, packet,
+ (struct sockaddr*)&pend->addr, pend->addrlen)) {
+ portcomm_loweruse(outnet, pend->pc);
+ return 0;
+ }
}
/* system calls to set timeout after sending UDP to make roundtrip
@@ -1273,45 +1953,152 @@ outnet_tcptimer(void* arg)
{
struct waiting_tcp* w = (struct waiting_tcp*)arg;
struct outside_network* outnet = w->outnet;
- comm_point_callback_type* cb;
- void* cb_arg;
- if(w->pkt) {
+ verbose(VERB_CLIENT, "outnet_tcptimer");
+ if(w->on_tcp_waiting_list) {
/* it is on the waiting list */
waiting_list_remove(outnet, w);
+ waiting_tcp_callback(w, NULL, NETEVENT_TIMEOUT, NULL);
+ waiting_tcp_delete(w);
} else {
/* it was in use */
struct pending_tcp* pend=(struct pending_tcp*)w->next_waiting;
- if(pend->c->ssl) {
-#ifdef HAVE_SSL
- SSL_shutdown(pend->c->ssl);
- SSL_free(pend->c->ssl);
- pend->c->ssl = NULL;
-#endif
- }
- comm_point_close(pend->c);
- pend->query = NULL;
- pend->next_free = outnet->tcp_free;
- outnet->tcp_free = pend;
+ reuse_cb_and_decommission(outnet, pend, NETEVENT_TIMEOUT);
}
- cb = w->cb;
- cb_arg = w->cb_arg;
- waiting_tcp_delete(w);
- fptr_ok(fptr_whitelist_pending_tcp(cb));
- (void)(*cb)(NULL, cb_arg, NETEVENT_TIMEOUT, NULL);
use_free_buffer(outnet);
}
+/** close the oldest reuse_tcp connection to make a fd and struct pend
+ * available for a new stream connection */
+static void
+reuse_tcp_close_oldest(struct outside_network* outnet)
+{
+ struct pending_tcp* pend;
+ verbose(VERB_CLIENT, "reuse_tcp_close_oldest");
+ if(!outnet->tcp_reuse_last) return;
+ pend = outnet->tcp_reuse_last->pending;
+
+ /* snip off of LRU */
+ log_assert(pend->reuse.lru_next == NULL);
+ if(pend->reuse.lru_prev) {
+ outnet->tcp_reuse_last = pend->reuse.lru_prev;
+ pend->reuse.lru_prev->lru_next = NULL;
+ } else {
+ outnet->tcp_reuse_last = NULL;
+ outnet->tcp_reuse_first = NULL;
+ }
+ pend->reuse.item_on_lru_list = 0;
+
+ /* free up */
+ reuse_cb_and_decommission(outnet, pend, NETEVENT_CLOSED);
+}
+
+/** find spare ID value for reuse tcp stream. That is random and also does
+ * not collide with an existing query ID that is in use or waiting */
+uint16_t
+reuse_tcp_select_id(struct reuse_tcp* reuse, struct outside_network* outnet)
+{
+ uint16_t id = 0, curid, nextid;
+ const int try_random = 2000;
+ int i;
+ unsigned select, count, space;
+ rbnode_type* node;
+
+ /* make really sure the tree is not empty */
+ if(reuse->tree_by_id.count == 0) {
+ id = ((unsigned)ub_random(outnet->rnd)>>8) & 0xffff;
+ return id;
+ }
+
+ /* try to find random empty spots by picking them */
+ for(i = 0; i<try_random; i++) {
+ id = ((unsigned)ub_random(outnet->rnd)>>8) & 0xffff;
+ if(!reuse_tcp_by_id_find(reuse, id)) {
+ return id;
+ }
+ }
+
+ /* equally pick a random unused element from the tree that is
+ * not in use. Pick a the n-th index of an ununused 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);
+ /* select value now in 0 .. num free - 1 */
+
+ count = 0; /* number of free spaces passed by */
+ node = rbtree_first(&reuse->tree_by_id);
+ log_assert(node && node != RBTREE_NULL); /* tree not empty */
+ /* see if select is before first node */
+ if(select < tree_by_id_get_id(node))
+ return select;
+ count += tree_by_id_get_id(node);
+ /* perhaps select is between nodes */
+ while(node && node != RBTREE_NULL) {
+ rbnode_type* next = rbtree_next(node);
+ if(next && next != RBTREE_NULL) {
+ curid = tree_by_id_get_id(node);
+ nextid = tree_by_id_get_id(next);
+ log_assert(curid < nextid);
+ if(curid != 0xffff && curid + 1 < nextid) {
+ /* space between nodes */
+ space = nextid - curid - 1;
+ log_assert(select >= count);
+ if(select < count + space) {
+ /* here it is */
+ return curid + 1 + (select - count);
+ }
+ count += space;
+ }
+ }
+ node = next;
+ }
+
+ /* select is after the last node */
+ /* count is the number of free positions before the nodes in the
+ * tree */
+ node = rbtree_last(&reuse->tree_by_id);
+ log_assert(node && node != RBTREE_NULL); /* tree not empty */
+ curid = tree_by_id_get_id(node);
+ log_assert(count + (0xffff-curid) + reuse->tree_by_id.count == 0xffff);
+ return curid + 1 + (select - count);
+}
+
struct waiting_tcp*
pending_tcp_query(struct serviced_query* sq, sldns_buffer* packet,
int timeout, comm_point_callback_type* callback, void* callback_arg)
{
struct pending_tcp* pend = sq->outnet->tcp_free;
+ struct reuse_tcp* reuse = NULL;
struct waiting_tcp* w;
- struct timeval tv;
- uint16_t id;
- /* if no buffer is free allocate space to store query */
+
+ verbose(VERB_CLIENT, "pending_tcp_query");
+ if(sldns_buffer_limit(packet) < sizeof(uint16_t)) {
+ verbose(VERB_ALGO, "pending tcp query with too short buffer < 2");
+ return NULL;
+ }
+
+ /* find out if a reused stream to the target exists */
+ /* if so, take it into use */
+ reuse = reuse_tcp_find(sq->outnet, &sq->addr, sq->addrlen,
+ sq->ssl_upstream);
+ if(reuse) {
+ log_reuse_tcp(VERB_CLIENT, "pending_tcp_query: found reuse", reuse);
+ log_assert(reuse->pending);
+ pend = reuse->pending;
+ reuse_tcp_lru_touch(sq->outnet, reuse);
+ }
+
+ /* if !pend but we have reuse streams, close a reuse stream
+ * to be able to open a new one to this target, no use waiting
+ * to reuse a file descriptor while another query needs to use
+ * that buffer and file descriptor now. */
+ if(!pend) {
+ reuse_tcp_close_oldest(sq->outnet);
+ pend = sq->outnet->tcp_free;
+ }
+
+ /* allocate space to store query */
w = (struct waiting_tcp*)malloc(sizeof(struct waiting_tcp)
- + (pend?0:sldns_buffer_limit(packet)));
+ + sldns_buffer_limit(packet));
if(!w) {
return NULL;
}
@@ -1319,47 +2106,76 @@ pending_tcp_query(struct serviced_query* sq, sldns_buffer* packet,
free(w);
return NULL;
}
- w->pkt = NULL;
- w->pkt_len = 0;
- id = ((unsigned)ub_random(sq->outnet->rnd)>>8) & 0xffff;
- LDNS_ID_SET(sldns_buffer_begin(packet), id);
+ w->pkt = (uint8_t*)w + sizeof(struct waiting_tcp);
+ w->pkt_len = sldns_buffer_limit(packet);
+ memmove(w->pkt, sldns_buffer_begin(packet), w->pkt_len);
+ if(reuse)
+ w->id = reuse_tcp_select_id(reuse, sq->outnet);
+ else w->id = ((unsigned)ub_random(sq->outnet->rnd)>>8) & 0xffff;
+ LDNS_ID_SET(w->pkt, w->id);
memcpy(&w->addr, &sq->addr, sq->addrlen);
w->addrlen = sq->addrlen;
w->outnet = sq->outnet;
+ w->on_tcp_waiting_list = 0;
+ w->next_waiting = NULL;
w->cb = callback;
w->cb_arg = callback_arg;
w->ssl_upstream = sq->ssl_upstream;
w->tls_auth_name = sq->tls_auth_name;
-#ifndef S_SPLINT_S
- tv.tv_sec = timeout/1000;
- tv.tv_usec = (timeout%1000)*1000;
-#endif
- comm_timer_set(w->timer, &tv);
+ w->timeout = timeout;
+ w->id_node.key = NULL;
+ w->write_wait_prev = NULL;
+ w->write_wait_next = NULL;
+ w->write_wait_queued = 0;
+ w->error_count = 0;
if(pend) {
/* we have a buffer available right now */
- if(!outnet_tcp_take_into_use(w, sldns_buffer_begin(packet),
- sldns_buffer_limit(packet))) {
- waiting_tcp_delete(w);
- return NULL;
+ if(reuse) {
+ /* reuse existing fd, write query and continue */
+ /* store query in tree by id */
+ verbose(VERB_CLIENT, "pending_tcp_query: reuse, store");
+ w->next_waiting = (void*)pend;
+ reuse_tree_by_id_insert(&pend->reuse, w);
+ /* can we write right now? */
+ if(pend->query == NULL) {
+ /* write straight away */
+ /* stop the timer on read of the fd */
+ comm_point_stop_listening(pend->c);
+ pend->query = w;
+ outnet_tcp_take_query_setup(pend->c->fd, pend,
+ w);
+ } else {
+ /* put it in the waiting list for
+ * this stream */
+ reuse_write_wait_push_back(&pend->reuse, w);
+ }
+ } else {
+ /* create new fd and connect to addr, setup to
+ * write query */
+ verbose(VERB_CLIENT, "pending_tcp_query: new fd, connect");
+ rbtree_init(&pend->reuse.tree_by_id, reuse_id_cmp);
+ pend->reuse.pending = pend;
+ memcpy(&pend->reuse.addr, &sq->addr, sq->addrlen);
+ pend->reuse.addrlen = sq->addrlen;
+ if(!outnet_tcp_take_into_use(w)) {
+ waiting_tcp_delete(w);
+ return NULL;
+ }
}
-#ifdef USE_DNSTAP
- if(sq->outnet->dtenv &&
- (sq->outnet->dtenv->log_resolver_query_messages ||
- sq->outnet->dtenv->log_forwarder_query_messages))
- dt_msg_send_outside_query(sq->outnet->dtenv, &sq->addr,
- comm_tcp, sq->zone, sq->zonelen, packet);
-#endif
} else {
/* queue up */
- w->pkt = (uint8_t*)w + sizeof(struct waiting_tcp);
- w->pkt_len = sldns_buffer_limit(packet);
- memmove(w->pkt, sldns_buffer_begin(packet), w->pkt_len);
- w->next_waiting = NULL;
- if(sq->outnet->tcp_wait_last)
- sq->outnet->tcp_wait_last->next_waiting = w;
- else sq->outnet->tcp_wait_first = w;
- sq->outnet->tcp_wait_last = w;
+ /* waiting for a buffer on the outside network buffer wait
+ * list */
+ verbose(VERB_CLIENT, "pending_tcp_query: queue to wait");
+ outnet_add_tcp_waiting(sq->outnet, w);
}
+#ifdef USE_DNSTAP
+ if(sq->outnet->dtenv &&
+ (sq->outnet->dtenv->log_resolver_query_messages ||
+ sq->outnet->dtenv->log_forwarder_query_messages))
+ dt_msg_send_outside_query(sq->outnet->dtenv, &sq->addr,
+ comm_tcp, sq->zone, sq->zonelen, packet);
+#endif
return w;
}
@@ -1477,6 +2293,7 @@ static void
waiting_list_remove(struct outside_network* outnet, struct waiting_tcp* w)
{
struct waiting_tcp* p = outnet->tcp_wait_first, *prev = NULL;
+ w->on_tcp_waiting_list = 0;
while(p) {
if(p == w) {
/* remove w */
@@ -1492,10 +2309,53 @@ waiting_list_remove(struct outside_network* outnet, struct waiting_tcp* w)
}
}
+/** reuse tcp stream, remove serviced query from stream,
+ * return true if the stream is kept, false if it is to be closed */
+static int
+reuse_tcp_remove_serviced_keep(struct waiting_tcp* w,
+ struct serviced_query* sq)
+{
+ struct pending_tcp* pend_tcp = (struct pending_tcp*)w->next_waiting;
+ verbose(VERB_CLIENT, "reuse_tcp_remove_serviced_keep");
+ /* remove the callback. let query continue to write to not cancel
+ * the stream itself. also keep it as an entry in the tree_by_id,
+ * in case the answer returns (that we no longer want), but we cannot
+ * pick the same ID number meanwhile */
+ w->cb = NULL;
+ /* see if can be entered in reuse tree
+ * for that the FD has to be non-1 */
+ if(pend_tcp->c->fd == -1) {
+ verbose(VERB_CLIENT, "reuse_tcp_remove_serviced_keep: -1 fd");
+ return 0;
+ }
+ /* if in tree and used by other queries */
+ if(pend_tcp->reuse.node.key) {
+ verbose(VERB_CLIENT, "reuse_tcp_remove_serviced_keep: in use by other queries");
+ /* do not reset the keepalive timer, for that
+ * we'd need traffic, and this is where the serviced is
+ * removed due to state machine internal reasons,
+ * eg. iterator no longer interested in this query */
+ return 1;
+ }
+ /* if still open and want to keep it open */
+ if(pend_tcp->c->fd != -1 && sq->outnet->tcp_reuse.count <
+ sq->outnet->tcp_reuse_max) {
+ verbose(VERB_CLIENT, "reuse_tcp_remove_serviced_keep: keep open");
+ /* set a keepalive timer on it */
+ if(!reuse_tcp_insert(sq->outnet, pend_tcp)) {
+ return 0;
+ }
+ reuse_tcp_setup_timeout(pend_tcp);
+ return 1;
+ }
+ return 0;
+}
+
/** cleanup serviced query entry */
static void
serviced_delete(struct serviced_query* sq)
{
+ verbose(VERB_CLIENT, "serviced_delete");
if(sq->pending) {
/* clear up the pending query */
if(sq->status == serviced_query_UDP_EDNS ||
@@ -1503,6 +2363,7 @@ serviced_delete(struct serviced_query* sq)
sq->status == serviced_query_UDP_EDNS_FRAG ||
sq->status == serviced_query_UDP_EDNS_fallback) {
struct pending* p = (struct pending*)sq->pending;
+ verbose(VERB_CLIENT, "serviced_delete: UDP");
if(p->pc)
portcomm_loweruse(sq->outnet, p->pc);
pending_delete(sq->outnet, p);
@@ -1510,14 +2371,32 @@ serviced_delete(struct serviced_query* sq)
* mesh */
outnet_send_wait_udp(sq->outnet);
} else {
- struct waiting_tcp* p = (struct waiting_tcp*)
+ struct waiting_tcp* w = (struct waiting_tcp*)
sq->pending;
- if(p->pkt == NULL) {
- decommission_pending_tcp(sq->outnet,
- (struct pending_tcp*)p->next_waiting);
+ verbose(VERB_CLIENT, "serviced_delete: TCP");
+ /* 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);
+ reuse_write_wait_remove(&pend->reuse, w);
+ 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");
+ if(!reuse_tcp_remove_serviced_keep(w, sq)) {
+ reuse_cb_and_decommission(sq->outnet,
+ pend, NETEVENT_CLOSED);
+ use_free_buffer(sq->outnet);
+ }
+ sq->pending = NULL;
} else {
- waiting_list_remove(sq->outnet, p);
- waiting_tcp_delete(p);
+ verbose(VERB_CLIENT, "serviced_delete: tcpwait");
+ waiting_list_remove(sq->outnet, w);
+ waiting_tcp_delete(w);
}
}
}
@@ -2097,18 +2976,18 @@ outnet_serviced_query(struct outside_network* outnet,
{
struct serviced_query* sq;
struct service_callback* cb;
- struct edns_tag_addr* client_tag_addr;
+ struct edns_string_addr* client_string_addr;
if(!inplace_cb_query_call(env, qinfo, flags, addr, addrlen, zone, zonelen,
qstate, qstate->region))
return NULL;
- if((client_tag_addr = edns_tag_addr_lookup(&env->edns_tags->client_tags,
- addr, addrlen))) {
- uint16_t client_tag = htons(client_tag_addr->tag_data);
+ if((client_string_addr = edns_string_addr_lookup(
+ &env->edns_strings->client_strings, addr, addrlen))) {
edns_opt_list_append(&qstate->edns_opts_back_out,
- env->edns_tags->client_tag_opcode, 2,
- (uint8_t*)&client_tag, qstate->region);
+ env->edns_strings->client_string_opcode,
+ client_string_addr->string_len,
+ client_string_addr->string, qstate->region);
}
serviced_gen_query(buff, qinfo->qname, qinfo->qname_len, qinfo->qtype,
diff --git a/contrib/unbound/services/outside_network.h b/contrib/unbound/services/outside_network.h
index c8f6d5724a87..2fe97fa6c5c9 100644
--- a/contrib/unbound/services/outside_network.h
+++ b/contrib/unbound/services/outside_network.h
@@ -52,6 +52,7 @@ struct ub_randstate;
struct pending_tcp;
struct waiting_tcp;
struct waiting_udp;
+struct reuse_tcp;
struct infra_cache;
struct port_comm;
struct port_if;
@@ -106,6 +107,9 @@ struct outside_network {
int delayclose;
/** timeout for delayclose */
struct timeval delay_tv;
+ /** if we perform udp-connect, connect() for UDP socket to mitigate
+ * ICMP side channel leakage */
+ int udp_connect;
/** array of outgoing IP4 interfaces */
struct port_if* ip4_ifs;
@@ -154,6 +158,21 @@ struct outside_network {
size_t num_tcp;
/** number of tcp communication points in use. */
size_t num_tcp_outgoing;
+ /**
+ * tree of still-open and waiting tcp connections for reuse.
+ * can be closed and reopened to get a new tcp connection.
+ * or reused to the same destination again. with timeout to close.
+ * Entries are of type struct reuse_tcp.
+ * The entries are both active and empty connections.
+ */
+ rbtree_type tcp_reuse;
+ /** max number of tcp_reuse entries we want to keep open */
+ size_t tcp_reuse_max;
+ /** first and last(oldest) in lru list of reuse connections.
+ * the oldest can be closed to get a new free pending_tcp if needed
+ * The list contains empty connections, that wait for timeout or
+ * a new query that can use the existing connection. */
+ struct reuse_tcp* tcp_reuse_first, *tcp_reuse_last;
/** list of tcp comm points that are free for use */
struct pending_tcp* tcp_free;
/** list of tcp queries waiting for a buffer */
@@ -212,6 +231,76 @@ struct port_comm {
};
/**
+ * Reuse TCP connection, still open can be used again.
+ */
+struct reuse_tcp {
+ /** rbtree node with links in tcp_reuse tree. key is NULL when not
+ * in tree. Both active and empty connections are in the tree.
+ * key is a pointer to this structure, the members used to compare
+ * are the sockaddr and and then is-ssl bool, and then ptr value is
+ * used in case the same address exists several times in the tree
+ * when there are multiple connections to the same destination to
+ * make the rbtree items unique. */
+ rbnode_type node;
+ /** the key for the tcp_reuse tree. address of peer, ip4 or ip6,
+ * and port number of peer */
+ struct sockaddr_storage addr;
+ /** length of addr */
+ socklen_t addrlen;
+ /** also key for tcp_reuse tree, if ssl is used */
+ int is_ssl;
+ /** lru chain, so that the oldest can be removed to get a new
+ * connection when all are in (re)use. oldest is last in list.
+ * The lru only contains empty connections waiting for reuse,
+ * the ones with active queries are not on the list because they
+ * do not need to be closed to make space for others. They already
+ * service a query so the close for another query does not help
+ * service a larger number of queries. */
+ struct reuse_tcp* lru_next, *lru_prev;
+ /** true if the reuse_tcp item is on the lru list with empty items */
+ int item_on_lru_list;
+ /** the connection to reuse, the fd is non-1 and is open.
+ * the addr and port determine where the connection is going,
+ * and is key to the rbtree. The SSL ptr determines if it is
+ * a TLS connection or a plain TCP connection there. And TLS
+ * or not is also part of the key to the rbtree.
+ * There is a timeout and read event on the fd, to close it. */
+ struct pending_tcp* pending;
+ /**
+ * The more read again value pointed to by the commpoint
+ * tcp_more_read_again pointer, so that it exists after commpoint
+ * delete
+ */
+ int cp_more_read_again;
+ /**
+ * The more write again value pointed to by the commpoint
+ * tcp_more_write_again pointer, so that it exists after commpoint
+ * delete
+ */
+ int cp_more_write_again;
+ /** rbtree with other queries waiting on the connection, by ID number,
+ * of type struct waiting_tcp. It is for looking up received
+ * answers to the structure for callback. And also to see if ID
+ * numbers are unused and can be used for a new query.
+ * The write_wait elements are also in the tree, so that ID numbers
+ * can be looked up also for them. They are bool write_wait_queued. */
+ rbtree_type tree_by_id;
+ /** list of queries waiting to be written on the channel,
+ * if NULL no queries are waiting to be written and the pending->query
+ * is the query currently serviced. The first is the next in line.
+ * They are also in the tree_by_id. Once written, the are removed
+ * from this list, but stay in the tree. */
+ struct waiting_tcp* write_wait_first, *write_wait_last;
+ /** the outside network it is part of */
+ struct outside_network* outnet;
+};
+
+/** max number of queries on a reuse connection */
+#define MAX_REUSE_TCP_QUERIES 200
+/** timeout for REUSE entries in milliseconds. */
+#define REUSE_TIMEOUT 60000
+
+/**
* A query that has an answer pending for it.
*/
struct pending {
@@ -255,12 +344,15 @@ struct pending {
struct pending_tcp {
/** next in list of free tcp comm points, or NULL. */
struct pending_tcp* next_free;
- /** the ID for the query; checked in reply */
- uint16_t id;
/** tcp comm point it was sent on (and reply must come back on). */
struct comm_point* c;
/** the query being serviced, NULL if the pending_tcp is unused. */
struct waiting_tcp* query;
+ /** the pre-allocated reuse tcp structure. if ->pending is nonNULL
+ * it is in use and the connection is waiting for reuse.
+ * It is here for memory pre-allocation, and used to make this
+ * pending_tcp wait for reuse. */
+ struct reuse_tcp reuse;
};
/**
@@ -269,12 +361,27 @@ struct pending_tcp {
struct waiting_tcp {
/**
* next in waiting list.
- * if pkt==0, this points to the pending_tcp structure.
+ * if on_tcp_waiting_list==0, this points to the pending_tcp structure.
*/
struct waiting_tcp* next_waiting;
+ /** if true the item is on the tcp waiting list and next_waiting
+ * is used for that. If false, the next_waiting points to the
+ * pending_tcp */
+ int on_tcp_waiting_list;
+ /** next and prev in query waiting list for stream connection */
+ struct waiting_tcp* write_wait_prev, *write_wait_next;
+ /** true if the waiting_tcp structure is on the write_wait queue */
+ int write_wait_queued;
+ /** entry in reuse.tree_by_id, if key is NULL, not in tree, otherwise,
+ * this struct is key and sorted by ID (from waiting_tcp.id). */
+ rbnode_type id_node;
+ /** the ID for the query; checked in reply */
+ uint16_t id;
/** timeout event; timer keeps running whether the query is
* waiting for a buffer or the tcp reply is pending */
struct comm_timer* timer;
+ /** timeout in msec */
+ int timeout;
/** the outside network it is part of */
struct outside_network* outnet;
/** remote address. */
@@ -284,13 +391,14 @@ struct waiting_tcp {
/**
* The query itself, the query packet to send.
* allocated after the waiting_tcp structure.
- * set to NULL when the query is serviced and it part of pending_tcp.
- * if this is NULL, the next_waiting points to the pending_tcp.
*/
uint8_t* pkt;
/** length of query packet. */
size_t pkt_len;
- /** callback for the timeout, error or reply to the message */
+ /** callback for the timeout, error or reply to the message,
+ * or NULL if no user is waiting. the entry uses an ID number.
+ * a query that was written is no longer needed, but the ID number
+ * and a reply will come back and can be ignored if NULL */
comm_point_callback_type* cb;
/** callback user argument */
void* cb_arg;
@@ -298,6 +406,8 @@ struct waiting_tcp {
int ssl_upstream;
/** ref to the tls_auth_name from the serviced_query */
char* tls_auth_name;
+ /** the packet was involved in an error, to stop looping errors */
+ int error_count;
};
/**
@@ -421,6 +531,7 @@ struct serviced_query {
* msec to wait on timeouted udp sockets.
* @param tls_use_sni: if SNI is used for TLS connections.
* @param dtenv: environment to send dnstap events with (if enabled).
+ * @param udp_connect: if the udp_connect option is enabled.
* @return: the new structure (with no pending answers) or NULL on error.
*/
struct outside_network* outside_network_create(struct comm_base* base,
@@ -429,7 +540,8 @@ struct outside_network* outside_network_create(struct comm_base* base,
struct ub_randstate* rnd, int use_caps_for_id, int* availports,
int numavailports, size_t unwanted_threshold, int tcp_mss,
void (*unwanted_action)(void*), void* unwanted_param, int do_udp,
- void* sslctx, int delayclose, int tls_use_sni, struct dt_env *dtenv);
+ void* sslctx, int delayclose, int tls_use_sni, struct dt_env *dtenv,
+ int udp_connect);
/**
* Delete outside_network structure.
@@ -546,6 +658,19 @@ size_t outnet_get_mem(struct outside_network* outnet);
*/
size_t serviced_get_mem(struct serviced_query* sq);
+/** Pick random ID value for a tcp stream, avoids existing IDs. */
+uint16_t reuse_tcp_select_id(struct reuse_tcp* reuse,
+ struct outside_network* outnet);
+
+/** find element in tree by id */
+struct waiting_tcp* reuse_tcp_by_id_find(struct reuse_tcp* reuse, uint16_t id);
+
+/** insert element in tree by id */
+void reuse_tree_by_id_insert(struct reuse_tcp* reuse, struct waiting_tcp* w);
+
+/** delete readwait waiting_tcp elements, deletes the elements in the list */
+void reuse_del_readwait(rbtree_type* tree_by_id);
+
/** get TCP file descriptor for address, returns -1 on failure,
* tcp_mss is 0 or maxseg size to set for TCP packets. */
int outnet_get_tcp_fd(struct sockaddr_storage* addr, socklen_t addrlen, int tcp_mss, int dscp);
@@ -643,4 +768,10 @@ int pending_cmp(const void* key1, const void* key2);
/** compare function of serviced query rbtree */
int serviced_cmp(const void* key1, const void* key2);
+/** compare function of reuse_tcp rbtree in outside_network struct */
+int reuse_cmp(const void* key1, const void* key2);
+
+/** compare function of reuse_tcp tree_by_id rbtree */
+int reuse_id_cmp(const void* key1, const void* key2);
+
#endif /* OUTSIDE_NETWORK_H */
diff --git a/contrib/unbound/services/rpz.c b/contrib/unbound/services/rpz.c
index ba5dd186daad..13304652cc02 100644
--- a/contrib/unbound/services/rpz.c
+++ b/contrib/unbound/services/rpz.c
@@ -440,6 +440,8 @@ err:
respip_set_delete(r->respip_set);
if(r->taglist)
free(r->taglist);
+ if(r->region)
+ regional_destroy(r->region);
free(r);
}
return NULL;
diff --git a/contrib/unbound/smallapp/unbound-control-setup.sh.in b/contrib/unbound/smallapp/unbound-control-setup.sh.in
index 3e506e84e236..eaf1d082cb76 100755
--- a/contrib/unbound/smallapp/unbound-control-setup.sh.in
+++ b/contrib/unbound/smallapp/unbound-control-setup.sh.in
@@ -120,12 +120,19 @@ if [ ! -f "$SVR_BASE.key" ]; then
fi
cat >server.cnf <<EOF
+[req]
default_bits=$BITS
default_md=$HASH
prompt=no
distinguished_name=req_distinguished_name
+x509_extensions=v3_ca
[req_distinguished_name]
commonName=$SERVERNAME
+[v3_ca]
+subjectKeyIdentifier=hash
+authorityKeyIdentifier=keyid:always,issuer:always
+basicConstraints=critical,CA:TRUE,pathlen:0
+subjectAltName=DNS:$SERVERNAME
EOF
[ -f server.cnf ] || fatal "cannot create openssl configuration"
@@ -156,8 +163,12 @@ default_bits=$BITS
default_md=$HASH
prompt=no
distinguished_name=req_distinguished_name
+req_extensions=v3_req
[req_distinguished_name]
commonName=$CLIENTNAME
+[v3_req]
+basicConstraints=critical,CA:FALSE
+subjectAltName=DNS:$CLIENTNAME
EOF
[ -f client.cnf ] || fatal "cannot create openssl configuration"
@@ -179,6 +190,8 @@ if [ ! -f "$CTL_BASE.pem" -o $RECREATE -eq 1 ]; then
-CAkey "$SVR_BASE.key" \
-CAcreateserial \
-$HASH \
+ -extfile client.cnf \
+ -extensions v3_req \
-out "$CTL_BASE.pem"
[ ! -f "CTL_BASE.pem" ] || fatal "cannot create signed client certificate"
diff --git a/contrib/unbound/util/config_file.c b/contrib/unbound/util/config_file.c
index acc0d1804c83..81009fedac14 100644
--- a/contrib/unbound/util/config_file.c
+++ b/contrib/unbound/util/config_file.c
@@ -170,7 +170,9 @@ config_create(void)
cfg->infra_cache_slabs = 4;
cfg->infra_cache_numhosts = 10000;
cfg->infra_cache_min_rtt = 50;
+ cfg->infra_keep_probing = 0;
cfg->delay_close = 0;
+ cfg->udp_connect = 1;
if(!(cfg->outgoing_avail_ports = (int*)calloc(65536, sizeof(int))))
goto error_exit;
init_outgoing_availports(cfg->outgoing_avail_ports, 65536);
@@ -321,8 +323,8 @@ config_create(void)
cfg->qname_minimisation_strict = 0;
cfg->shm_enable = 0;
cfg->shm_key = 11777;
- cfg->edns_client_tags = NULL;
- cfg->edns_client_tag_opcode = LDNS_EDNS_CLIENT_TAG;
+ cfg->edns_client_strings = NULL;
+ cfg->edns_client_string_opcode = 65001;
cfg->dnscrypt = 0;
cfg->dnscrypt_port = 0;
cfg->dnscrypt_provider = NULL;
@@ -522,11 +524,12 @@ int config_set_option(struct config_file* cfg, const char* opt,
else S_STR("tls-ciphersuites:", tls_ciphersuites)
else S_YNO("tls-use-sni:", tls_use_sni)
else S_NUMBER_NONZERO("https-port:", https_port)
- else S_STR("http-endpoint", http_endpoint)
- else S_NUMBER_NONZERO("http-max-streams", http_max_streams)
- else S_MEMSIZE("http-query-buffer-size", http_query_buffer_size)
- else S_MEMSIZE("http-response-buffer-size", http_response_buffer_size)
- else S_YNO("http-nodelay", http_nodelay)
+ else S_STR("http-endpoint:", http_endpoint)
+ else S_NUMBER_NONZERO("http-max-streams:", http_max_streams)
+ else S_MEMSIZE("http-query-buffer-size:", http_query_buffer_size)
+ else S_MEMSIZE("http-response-buffer-size:", http_response_buffer_size)
+ else S_YNO("http-nodelay:", http_nodelay)
+ else S_YNO("http-notls-downstream:", http_notls_downstream)
else S_YNO("interface-automatic:", if_automatic)
else S_YNO("use-systemd:", use_systemd)
else S_YNO("do-daemonize:", do_daemonize)
@@ -562,10 +565,12 @@ int config_set_option(struct config_file* cfg, const char* opt,
IS_NUMBER_OR_ZERO; cfg->infra_cache_min_rtt = atoi(val);
RTT_MIN_TIMEOUT=cfg->infra_cache_min_rtt;
}
+ else S_YNO("infra-keep-probing:", infra_keep_probing)
else S_NUMBER_OR_ZERO("infra-host-ttl:", host_ttl)
else S_POW2("infra-cache-slabs:", infra_cache_slabs)
else S_SIZET_NONZERO("infra-cache-numhosts:", infra_cache_numhosts)
else S_NUMBER_OR_ZERO("delay-close:", delay_close)
+ else S_YNO("udp-connect:", udp_connect)
else S_STR("chroot:", chrootdir)
else S_STR("username:", username)
else S_STR("directory:", directory)
@@ -958,8 +963,10 @@ config_get_option(struct config_file* cfg, const char* opt,
else O_DEC(opt, "infra-host-ttl", host_ttl)
else O_DEC(opt, "infra-cache-slabs", infra_cache_slabs)
else O_DEC(opt, "infra-cache-min-rtt", infra_cache_min_rtt)
+ else O_YNO(opt, "infra-keep-probing", infra_keep_probing)
else O_MEM(opt, "infra-cache-numhosts", infra_cache_numhosts)
else O_UNS(opt, "delay-close", delay_close)
+ else O_YNO(opt, "udp-connect", udp_connect)
else O_YNO(opt, "do-ip4", do_ip4)
else O_YNO(opt, "do-ip6", do_ip6)
else O_YNO(opt, "do-udp", do_udp)
@@ -990,6 +997,7 @@ config_get_option(struct config_file* cfg, const char* opt,
else O_MEM(opt, "http-query-buffer-size", http_query_buffer_size)
else O_MEM(opt, "http-response-buffer-size", http_response_buffer_size)
else O_YNO(opt, "http-nodelay", http_nodelay)
+ else O_YNO(opt, "http-notls-downstream", http_notls_downstream)
else O_YNO(opt, "use-systemd", use_systemd)
else O_YNO(opt, "do-daemonize", do_daemonize)
else O_STR(opt, "chroot", chrootdir)
@@ -1150,7 +1158,7 @@ config_get_option(struct config_file* cfg, const char* opt,
else O_LS3(opt, "access-control-tag-action", acl_tag_actions)
else O_LS3(opt, "access-control-tag-data", acl_tag_datas)
else O_LS2(opt, "access-control-view", acl_view)
- else O_LS2(opt, "edns-client-tags", edns_client_tags)
+ else O_LS2(opt, "edns-client-strings", edns_client_strings)
#ifdef USE_IPSECMOD
else O_YNO(opt, "ipsecmod-enabled", ipsecmod_enabled)
else O_YNO(opt, "ipsecmod-ignore-bogus", ipsecmod_ignore_bogus)
@@ -1519,7 +1527,7 @@ config_delete(struct config_file* cfg)
config_deldblstrlist(cfg->ratelimit_below_domain);
config_delstrlist(cfg->python_script);
config_delstrlist(cfg->dynlib_file);
- config_deldblstrlist(cfg->edns_client_tags);
+ config_deldblstrlist(cfg->edns_client_strings);
#ifdef USE_IPSECMOD
free(cfg->ipsecmod_hook);
config_delstrlist(cfg->ipsecmod_whitelist);
diff --git a/contrib/unbound/util/config_file.h b/contrib/unbound/util/config_file.h
index 7750eaa0e6b0..556544021538 100644
--- a/contrib/unbound/util/config_file.h
+++ b/contrib/unbound/util/config_file.h
@@ -143,6 +143,8 @@ struct config_file {
size_t http_response_buffer_size;
/** set TCP_NODELAY option for http sockets */
int http_nodelay;
+ /** Disable TLS for http sockets downstream */
+ int http_notls_downstream;
/** outgoing port range number of ports (per thread) */
int outgoing_num_ports;
@@ -179,8 +181,12 @@ struct config_file {
size_t infra_cache_numhosts;
/** min value for infra cache rtt */
int infra_cache_min_rtt;
+ /** keep probing hosts that are down */
+ int infra_keep_probing;
/** delay close of udp-timeouted ports, if 0 no delayclose. in msec */
int delay_close;
+ /** udp_connect enable uses UDP connect to mitigate ICMP side channel */
+ int udp_connect;
/** the target fetch policy for the iterator */
char* target_fetch_policy;
@@ -562,10 +568,10 @@ struct config_file {
/** SHM data - key for the shm */
int shm_key;
- /** list of EDNS client tag entries, linked list */
- struct config_str2list* edns_client_tags;
- /** EDNS opcode to use for EDNS client tags */
- uint16_t edns_client_tag_opcode;
+ /** list of EDNS client string entries, linked list */
+ struct config_str2list* edns_client_strings;
+ /** EDNS opcode to use for EDNS client strings */
+ uint16_t edns_client_string_opcode;
/** DNSCrypt */
/** true to enable dnscrypt */
diff --git a/contrib/unbound/util/configlexer.lex b/contrib/unbound/util/configlexer.lex
index 8bf18b03bef9..e667746577a4 100644
--- a/contrib/unbound/util/configlexer.lex
+++ b/contrib/unbound/util/configlexer.lex
@@ -263,6 +263,7 @@ http-max-streams{COLON} { YDVAR(1, VAR_HTTP_MAX_STREAMS) }
http-query-buffer-size{COLON} { YDVAR(1, VAR_HTTP_QUERY_BUFFER_SIZE) }
http-response-buffer-size{COLON} { YDVAR(1, VAR_HTTP_RESPONSE_BUFFER_SIZE) }
http-nodelay{COLON} { YDVAR(1, VAR_HTTP_NODELAY) }
+http-notls-downstream{COLON} { YDVAR(1, VAR_HTTP_NOTLS_DOWNSTREAM) }
use-systemd{COLON} { YDVAR(1, VAR_USE_SYSTEMD) }
do-daemonize{COLON} { YDVAR(1, VAR_DO_DAEMONIZE) }
interface{COLON} { YDVAR(1, VAR_INTERFACE) }
@@ -297,9 +298,11 @@ infra-cache-slabs{COLON} { YDVAR(1, VAR_INFRA_CACHE_SLABS) }
infra-cache-numhosts{COLON} { YDVAR(1, VAR_INFRA_CACHE_NUMHOSTS) }
infra-cache-lame-size{COLON} { YDVAR(1, VAR_INFRA_CACHE_LAME_SIZE) }
infra-cache-min-rtt{COLON} { YDVAR(1, VAR_INFRA_CACHE_MIN_RTT) }
+infra-keep-probing{COLON} { YDVAR(1, VAR_INFRA_KEEP_PROBING) }
num-queries-per-thread{COLON} { YDVAR(1, VAR_NUM_QUERIES_PER_THREAD) }
jostle-timeout{COLON} { YDVAR(1, VAR_JOSTLE_TIMEOUT) }
delay-close{COLON} { YDVAR(1, VAR_DELAY_CLOSE) }
+udp-connect{COLON} { YDVAR(1, VAR_UDP_CONNECT) }
target-fetch-policy{COLON} { YDVAR(1, VAR_TARGET_FETCH_POLICY) }
harden-short-bufsize{COLON} { YDVAR(1, VAR_HARDEN_SHORT_BUFSIZE) }
harden-large-queries{COLON} { YDVAR(1, VAR_HARDEN_LARGE_QUERIES) }
@@ -527,8 +530,8 @@ name-v4{COLON} { YDVAR(1, VAR_IPSET_NAME_V4) }
name-v6{COLON} { YDVAR(1, VAR_IPSET_NAME_V6) }
udp-upstream-without-downstream{COLON} { YDVAR(1, VAR_UDP_UPSTREAM_WITHOUT_DOWNSTREAM) }
tcp-connection-limit{COLON} { YDVAR(2, VAR_TCP_CONNECTION_LIMIT) }
-edns-client-tag{COLON} { YDVAR(2, VAR_EDNS_CLIENT_TAG) }
-edns-client-tag-opcode{COLON} { YDVAR(1, VAR_EDNS_CLIENT_TAG_OPCODE) }
+edns-client-string{COLON} { YDVAR(2, VAR_EDNS_CLIENT_STRING) }
+edns-client-string-opcode{COLON} { YDVAR(1, VAR_EDNS_CLIENT_STRING_OPCODE) }
<INITIAL,val>{NEWLINE} { LEXOUT(("NL\n")); cfg_parser->line++; }
/* Quoted strings. Strip leading and ending quotes */
diff --git a/contrib/unbound/util/configparser.y b/contrib/unbound/util/configparser.y
index 43a886f2403a..4d6b5e3fba31 100644
--- a/contrib/unbound/util/configparser.y
+++ b/contrib/unbound/util/configparser.y
@@ -114,11 +114,11 @@ extern struct config_parser_state* cfg_parser;
%token VAR_STUB_SSL_UPSTREAM VAR_FORWARD_SSL_UPSTREAM VAR_TLS_CERT_BUNDLE
%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
+%token VAR_HTTP_NODELAY VAR_HTTP_NOTLS_DOWNSTREAM
%token VAR_STUB_FIRST VAR_MINIMAL_RESPONSES VAR_RRSET_ROUNDROBIN
-%token VAR_MAX_UDP_SIZE VAR_DELAY_CLOSE
+%token VAR_MAX_UDP_SIZE VAR_DELAY_CLOSE VAR_UDP_CONNECT
%token VAR_UNBLOCK_LAN_ZONES VAR_INSECURE_LAN_ZONES
-%token VAR_INFRA_CACHE_MIN_RTT
+%token VAR_INFRA_CACHE_MIN_RTT VAR_INFRA_KEEP_PROBING
%token VAR_DNS64_PREFIX VAR_DNS64_SYNTHALL VAR_DNS64_IGNORE_AAAA
%token VAR_DNSTAP VAR_DNSTAP_ENABLE VAR_DNSTAP_SOCKET_PATH VAR_DNSTAP_IP
%token VAR_DNSTAP_TLS VAR_DNSTAP_TLS_SERVER_NAME VAR_DNSTAP_TLS_CERT_BUNDLE
@@ -178,7 +178,8 @@ extern struct config_parser_state* cfg_parser;
%token VAR_IPSET VAR_IPSET_NAME_V4 VAR_IPSET_NAME_V6
%token VAR_TLS_SESSION_TICKET_KEYS VAR_RPZ VAR_TAGS VAR_RPZ_ACTION_OVERRIDE
%token VAR_RPZ_CNAME_OVERRIDE VAR_RPZ_LOG VAR_RPZ_LOG_NAME
-%token VAR_DYNLIB VAR_DYNLIB_FILE VAR_EDNS_CLIENT_TAG VAR_EDNS_CLIENT_TAG_OPCODE
+%token VAR_DYNLIB VAR_DYNLIB_FILE VAR_EDNS_CLIENT_STRING
+%token VAR_EDNS_CLIENT_STRING_OPCODE
%%
toplevelvars: /* empty */ | toplevelvars toplevelvar ;
@@ -249,14 +250,14 @@ content_server: server_num_threads | server_verbosity | server_port |
server_ssl_service_key | server_ssl_service_pem | server_ssl_port |
server_https_port | server_http_endpoint | server_http_max_streams |
server_http_query_buffer_size | server_http_response_buffer_size |
- server_http_nodelay |
+ server_http_nodelay | server_http_notls_downstream |
server_minimal_responses | server_rrset_roundrobin | server_max_udp_size |
- server_so_reuseport | server_delay_close |
+ server_so_reuseport | server_delay_close | server_udp_connect |
server_unblock_lan_zones | server_insecure_lan_zones |
server_dns64_prefix | server_dns64_synthall | server_dns64_ignore_aaaa |
server_infra_cache_min_rtt | server_harden_algo_downgrade |
server_ip_transparent | server_ip_ratelimit | server_ratelimit |
- server_ip_dscp |
+ server_ip_dscp | server_infra_keep_probing |
server_ip_ratelimit_slabs | server_ratelimit_slabs |
server_ip_ratelimit_size | server_ratelimit_size |
server_ratelimit_for_domain |
@@ -291,8 +292,8 @@ content_server: server_num_threads | server_verbosity | server_port |
server_unknown_server_time_limit | server_log_tag_queryreply |
server_stream_wait_size | server_tls_ciphers |
server_tls_ciphersuites | server_tls_session_ticket_keys |
- server_tls_use_sni | server_edns_client_tag |
- server_edns_client_tag_opcode
+ server_tls_use_sni | server_edns_client_string |
+ server_edns_client_string_opcode
;
stubstart: VAR_STUB_ZONE
{
@@ -982,6 +983,7 @@ server_https_port: VAR_HTTPS_PORT STRING_ARG
if(atoi($2) == 0)
yyerror("port number expected");
else cfg_parser->cfg->https_port = atoi($2);
+ free($2);
};
server_http_endpoint: VAR_HTTP_ENDPOINT STRING_ARG
{
@@ -1030,6 +1032,14 @@ server_http_nodelay: VAR_HTTP_NODELAY STRING_ARG
yyerror("expected yes or no.");
else cfg_parser->cfg->http_nodelay = (strcmp($2, "yes")==0);
free($2);
+ }
+server_http_notls_downstream: VAR_HTTP_NOTLS_DOWNSTREAM STRING_ARG
+ {
+ OUTYY(("P(server_http_notls_downstream:%s)\n", $2));
+ if(strcmp($2, "yes") != 0 && strcmp($2, "no") != 0)
+ yyerror("expected yes or no.");
+ else cfg_parser->cfg->http_notls_downstream = (strcmp($2, "yes")==0);
+ free($2);
};
server_use_systemd: VAR_USE_SYSTEMD STRING_ARG
{
@@ -1434,6 +1444,15 @@ server_delay_close: VAR_DELAY_CLOSE STRING_ARG
free($2);
}
;
+server_udp_connect: VAR_UDP_CONNECT STRING_ARG
+ {
+ OUTYY(("P(server_udp_connect:%s)\n", $2));
+ if(strcmp($2, "yes") != 0 && strcmp($2, "no") != 0)
+ yyerror("expected yes or no.");
+ else cfg_parser->cfg->udp_connect = (strcmp($2, "yes")==0);
+ free($2);
+ }
+ ;
server_unblock_lan_zones: VAR_UNBLOCK_LAN_ZONES STRING_ARG
{
OUTYY(("P(server_unblock_lan_zones:%s)\n", $2));
@@ -1531,6 +1550,16 @@ server_infra_cache_min_rtt: VAR_INFRA_CACHE_MIN_RTT STRING_ARG
free($2);
}
;
+server_infra_keep_probing: VAR_INFRA_KEEP_PROBING STRING_ARG
+ {
+ OUTYY(("P(server_infra_keep_probing:%s)\n", $2));
+ if(strcmp($2, "yes") != 0 && strcmp($2, "no") != 0)
+ yyerror("expected yes or no.");
+ else cfg_parser->cfg->infra_keep_probing =
+ (strcmp($2, "yes")==0);
+ free($2);
+ }
+ ;
server_target_fetch_policy: VAR_TARGET_FETCH_POLICY STRING_ARG
{
OUTYY(("P(server_target_fetch_policy:%s)\n", $2));
@@ -2465,29 +2494,24 @@ server_ipsecmod_strict: VAR_IPSECMOD_STRICT STRING_ARG
#endif
}
;
-server_edns_client_tag: VAR_EDNS_CLIENT_TAG STRING_ARG STRING_ARG
+server_edns_client_string: VAR_EDNS_CLIENT_STRING STRING_ARG STRING_ARG
{
- int tag_data;
- OUTYY(("P(server_edns_client_tag:%s %s)\n", $2, $3));
- tag_data = atoi($3);
- if(tag_data > 65535 || tag_data < 0 ||
- (tag_data == 0 && (strlen($3) != 1 || $3[0] != '0')))
- yyerror("edns-client-tag data invalid, needs to be a "
- "number from 0 to 65535");
+ OUTYY(("P(server_edns_client_string:%s %s)\n", $2, $3));
if(!cfg_str2list_insert(
- &cfg_parser->cfg->edns_client_tags, $2, $3))
+ &cfg_parser->cfg->edns_client_strings, $2, $3))
fatal_exit("out of memory adding "
- "edns-client-tag");
+ "edns-client-string");
}
;
-server_edns_client_tag_opcode: VAR_EDNS_CLIENT_TAG_OPCODE STRING_ARG
+server_edns_client_string_opcode: VAR_EDNS_CLIENT_STRING_OPCODE STRING_ARG
{
- OUTYY(("P(edns_client_tag_opcode:%s)\n", $2));
+ OUTYY(("P(edns_client_string_opcode:%s)\n", $2));
if(atoi($2) == 0 && strcmp($2, "0") != 0)
yyerror("option code expected");
else if(atoi($2) > 65535 || atoi($2) < 0)
yyerror("option code must be in interval [0, 65535]");
- else cfg_parser->cfg->edns_client_tag_opcode = atoi($2);
+ else cfg_parser->cfg->edns_client_string_opcode = atoi($2);
+ free($2);
}
;
diff --git a/contrib/unbound/util/data/msgencode.c b/contrib/unbound/util/data/msgencode.c
index be69f628a507..1746cfbb8fab 100644
--- a/contrib/unbound/util/data/msgencode.c
+++ b/contrib/unbound/util/data/msgencode.c
@@ -624,6 +624,9 @@ positive_answer(struct reply_info* rep, uint16_t qtype) {
for(i=0;i<rep->an_numrrsets; i++) {
if(ntohs(rep->rrsets[i]->rk.type) == qtype) {
+ /* for priming queries, type NS, include addresses */
+ if(qtype == LDNS_RR_TYPE_NS)
+ return 0;
/* in case it is a wildcard with DNSSEC, there will
* be NSEC/NSEC3 records in the authority section
* that we cannot remove */
diff --git a/contrib/unbound/util/data/msgreply.h b/contrib/unbound/util/data/msgreply.h
index 8d75f9b12f3a..385780268a3c 100644
--- a/contrib/unbound/util/data/msgreply.h
+++ b/contrib/unbound/util/data/msgreply.h
@@ -552,7 +552,7 @@ struct edns_option* edns_opt_list_find(struct edns_option* list, uint16_t code);
* @param rep: Reply info. Could be NULL.
* @param rcode: return code.
* @param edns: edns data of the reply.
- * @param repinfo: comm_reply. NULL.
+ * @param repinfo: comm_reply. Reply information for a communication point.
* @param region: region to store data.
* @return false on failure (a callback function returned an error).
*/
diff --git a/contrib/unbound/util/edns.c b/contrib/unbound/util/edns.c
index 6a7e4f8cf55a..503f96e097ab 100644
--- a/contrib/unbound/util/edns.c
+++ b/contrib/unbound/util/edns.c
@@ -53,81 +53,84 @@
#include "edns.h"
#endif
-struct edns_tags* edns_tags_create(void)
+struct edns_strings* edns_strings_create(void)
{
- struct edns_tags* edns_tags = calloc(1, sizeof(struct edns_tags));
- if(!edns_tags)
+ struct edns_strings* edns_strings = calloc(1,
+ sizeof(struct edns_strings));
+ if(!edns_strings)
return NULL;
- if(!(edns_tags->region = regional_create())) {
- edns_tags_delete(edns_tags);
+ if(!(edns_strings->region = regional_create())) {
+ edns_strings_delete(edns_strings);
return NULL;
}
- return edns_tags;
+ return edns_strings;
}
-void edns_tags_delete(struct edns_tags* edns_tags)
+void edns_strings_delete(struct edns_strings* edns_strings)
{
- if(!edns_tags)
+ if(!edns_strings)
return;
- regional_destroy(edns_tags->region);
- free(edns_tags);
+ regional_destroy(edns_strings->region);
+ free(edns_strings);
}
static int
-edns_tags_client_insert(struct edns_tags* edns_tags,
+edns_strings_client_insert(struct edns_strings* edns_strings,
struct sockaddr_storage* addr, socklen_t addrlen, int net,
- uint16_t tag_data)
+ const char* string)
{
- struct edns_tag_addr* eta = regional_alloc_zero(edns_tags->region,
- sizeof(struct edns_tag_addr));
- if(!eta)
+ struct edns_string_addr* esa = regional_alloc_zero(edns_strings->region,
+ sizeof(struct edns_string_addr));
+ if(!esa)
return 0;
- eta->tag_data = tag_data;
- if(!addr_tree_insert(&edns_tags->client_tags, &eta->node, addr, addrlen,
- net)) {
- verbose(VERB_QUERY, "duplicate EDNS client tag ignored.");
+ esa->string_len = strlen(string);
+ esa->string = regional_alloc_init(edns_strings->region, string,
+ esa->string_len);
+ if(!esa->string)
+ return 0;
+ if(!addr_tree_insert(&edns_strings->client_strings, &esa->node, addr,
+ addrlen, net)) {
+ verbose(VERB_QUERY, "duplicate EDNS client string ignored.");
}
return 1;
}
-int edns_tags_apply_cfg(struct edns_tags* edns_tags,
+int edns_strings_apply_cfg(struct edns_strings* edns_strings,
struct config_file* config)
{
struct config_str2list* c;
- regional_free_all(edns_tags->region);
- addr_tree_init(&edns_tags->client_tags);
+ regional_free_all(edns_strings->region);
+ addr_tree_init(&edns_strings->client_strings);
- for(c=config->edns_client_tags; c; c=c->next) {
+ for(c=config->edns_client_strings; c; c=c->next) {
struct sockaddr_storage addr;
socklen_t addrlen;
int net;
- uint16_t tag_data;
log_assert(c->str && c->str2);
if(!netblockstrtoaddr(c->str, UNBOUND_DNS_PORT, &addr, &addrlen,
&net)) {
- log_err("cannot parse EDNS client tag IP netblock: %s",
- c->str);
+ log_err("cannot parse EDNS client string IP netblock: "
+ "%s", c->str);
return 0;
}
- tag_data = atoi(c->str2); /* validated in config parser */
- if(!edns_tags_client_insert(edns_tags, &addr, addrlen, net,
- tag_data)) {
- log_err("out of memory while adding EDNS tags");
+ if(!edns_strings_client_insert(edns_strings, &addr, addrlen,
+ net, c->str2)) {
+ log_err("out of memory while adding EDNS strings");
return 0;
}
}
- edns_tags->client_tag_opcode = config->edns_client_tag_opcode;
+ edns_strings->client_string_opcode = config->edns_client_string_opcode;
- addr_tree_init_parents(&edns_tags->client_tags);
+ addr_tree_init_parents(&edns_strings->client_strings);
return 1;
}
-struct edns_tag_addr*
-edns_tag_addr_lookup(rbtree_type* tree, struct sockaddr_storage* addr,
+struct edns_string_addr*
+edns_string_addr_lookup(rbtree_type* tree, struct sockaddr_storage* addr,
socklen_t addrlen)
{
- return (struct edns_tag_addr*)addr_tree_lookup(tree, addr, addrlen);
+ return (struct edns_string_addr*)addr_tree_lookup(tree, addr, addrlen);
}
static int edns_keepalive(struct edns_data* edns_out, struct edns_data* edns_in,
diff --git a/contrib/unbound/util/edns.h b/contrib/unbound/util/edns.h
index cf9f8707e808..11742eb5b723 100644
--- a/contrib/unbound/util/edns.h
+++ b/contrib/unbound/util/edns.h
@@ -50,58 +50,60 @@ struct comm_point;
struct regional;
/**
- * Structure containing all EDNS tags.
+ * Structure containing all EDNS strings.
*/
-struct edns_tags {
- /** Tree of EDNS client tags to use in upstream queries, per address
- * prefix. Contains nodes of type edns_tag_addr. */
- rbtree_type client_tags;
- /** EDNS opcode to use for client tags */
- uint16_t client_tag_opcode;
+struct edns_strings {
+ /** Tree of EDNS client strings to use in upstream queries, per address
+ * prefix. Contains nodes of type edns_string_addr. */
+ rbtree_type client_strings;
+ /** EDNS opcode to use for client strings */
+ uint16_t client_string_opcode;
/** region to allocate tree nodes in */
struct regional* region;
};
/**
- * EDNS tag. Node of rbtree, containing tag and prefix.
+ * EDNS string. Node of rbtree, containing string and prefix.
*/
-struct edns_tag_addr {
+struct edns_string_addr {
/** node in address tree, used for tree lookups. Need to be the first
* member of this struct. */
struct addr_tree_node node;
- /** tag data, in host byte ordering */
- uint16_t tag_data;
+ /** string, ascii format */
+ uint8_t* string;
+ /** length of string */
+ size_t string_len;
};
/**
- * Create structure to hold EDNS tags
- * @return: newly created edns_tags, NULL on alloc failure.
+ * Create structure to hold EDNS strings
+ * @return: newly created edns_strings, NULL on alloc failure.
*/
-struct edns_tags* edns_tags_create(void);
+struct edns_strings* edns_strings_create(void);
-/** Delete EDNS tags structure
- * @param edns_tags: struct to delete
+/** Delete EDNS strings structure
+ * @param edns_strings: struct to delete
*/
-void edns_tags_delete(struct edns_tags* edns_tags);
+void edns_strings_delete(struct edns_strings* edns_strings);
/**
- * Add configured EDNS tags
- * @param edns_tags: edns tags to apply config to
- * @param config: struct containing EDNS tags configuration
+ * Add configured EDNS strings
+ * @param edns_strings: edns strings to apply config to
+ * @param config: struct containing EDNS strings configuration
* @return 0 on error
*/
-int edns_tags_apply_cfg(struct edns_tags* edns_tags,
+int edns_strings_apply_cfg(struct edns_strings* edns_strings,
struct config_file* config);
/**
- * Find tag for address.
- * @param tree: tree containing EDNS tags per address prefix.
+ * Find string for address.
+ * @param tree: tree containing EDNS strings per address prefix.
* @param addr: address to use for tree lookup
* @param addrlen: length of address
* @return: matching tree node, NULL otherwise
*/
-struct edns_tag_addr*
-edns_tag_addr_lookup(rbtree_type* tree, struct sockaddr_storage* addr,
+struct edns_string_addr*
+edns_string_addr_lookup(rbtree_type* tree, struct sockaddr_storage* addr,
socklen_t addrlen);
/**
diff --git a/contrib/unbound/util/fptr_wlist.c b/contrib/unbound/util/fptr_wlist.c
index 7d15d107561a..a9e9d3a03239 100644
--- a/contrib/unbound/util/fptr_wlist.c
+++ b/contrib/unbound/util/fptr_wlist.c
@@ -229,6 +229,8 @@ fptr_whitelist_rbtree_cmp(int (*fptr) (const void *, const void *))
else if(fptr == &fwd_cmp) return 1;
else if(fptr == &pending_cmp) return 1;
else if(fptr == &serviced_cmp) return 1;
+ else if(fptr == &reuse_cmp) return 1;
+ else if(fptr == &reuse_id_cmp) return 1;
else if(fptr == &name_tree_compare) return 1;
else if(fptr == &order_lock_cmp) return 1;
else if(fptr == &codeline_cmp) return 1;
diff --git a/contrib/unbound/util/iana_ports.inc b/contrib/unbound/util/iana_ports.inc
index fa25869d3b56..d9978f92eda0 100644
--- a/contrib/unbound/util/iana_ports.inc
+++ b/contrib/unbound/util/iana_ports.inc
@@ -5290,6 +5290,7 @@
22005,
22273,
22305,
+22333,
22335,
22343,
22347,
diff --git a/contrib/unbound/util/module.h b/contrib/unbound/util/module.h
index 1eed213008c2..7b833f8ade19 100644
--- a/contrib/unbound/util/module.h
+++ b/contrib/unbound/util/module.h
@@ -520,8 +520,8 @@ struct module_env {
struct edns_known_option* edns_known_options;
/* Number of known edns options */
size_t edns_known_options_num;
- /** EDNS client tag information */
- struct edns_tags* edns_tags;
+ /** EDNS client string information */
+ struct edns_strings* edns_strings;
/* Make every mesh state unique, do not aggregate mesh states. */
int unique_mesh;
diff --git a/contrib/unbound/util/netevent.c b/contrib/unbound/util/netevent.c
index 545f09742c7c..8bbad15920a2 100644
--- a/contrib/unbound/util/netevent.c
+++ b/contrib/unbound/util/netevent.c
@@ -341,10 +341,15 @@ comm_point_send_udp_msg(struct comm_point *c, sldns_buffer* packet,
if(sldns_buffer_remaining(packet) == 0)
log_err("error: send empty UDP packet");
#endif
- log_assert(addr && addrlen > 0);
- sent = sendto(c->fd, (void*)sldns_buffer_begin(packet),
- sldns_buffer_remaining(packet), 0,
- addr, addrlen);
+ if(addr) {
+ log_assert(addr && addrlen > 0);
+ sent = sendto(c->fd, (void*)sldns_buffer_begin(packet),
+ sldns_buffer_remaining(packet), 0,
+ addr, addrlen);
+ } else {
+ sent = send(c->fd, (void*)sldns_buffer_begin(packet),
+ sldns_buffer_remaining(packet), 0);
+ }
if(sent == -1) {
/* try again and block, waiting for IO to complete,
* we want to send the answer, and we will wait for
@@ -574,6 +579,32 @@ comm_point_send_udp_msg_if(struct comm_point *c, sldns_buffer* packet,
#endif /* AF_INET6 && IPV6_PKTINFO && HAVE_SENDMSG */
}
+/** return true is UDP receive error needs to be logged */
+static int udp_recv_needs_log(int err)
+{
+ switch(err) {
+ case ECONNREFUSED:
+# ifdef ENETUNREACH
+ case ENETUNREACH:
+# endif
+# ifdef EHOSTDOWN
+ case EHOSTDOWN:
+# endif
+# ifdef EHOSTUNREACH
+ case EHOSTUNREACH:
+# endif
+# ifdef ENETDOWN
+ case ENETDOWN:
+# endif
+ if(verbosity >= VERB_ALGO)
+ return 1;
+ return 0;
+ default:
+ break;
+ }
+ return 1;
+}
+
void
comm_point_udp_ancil_callback(int fd, short event, void* arg)
{
@@ -616,7 +647,8 @@ comm_point_udp_ancil_callback(int fd, short event, void* arg)
msg.msg_flags = 0;
rcv = recvmsg(fd, &msg, 0);
if(rcv == -1) {
- if(errno != EAGAIN && errno != EINTR) {
+ if(errno != EAGAIN && errno != EINTR
+ && udp_recv_needs_log(errno)) {
log_err("recvmsg failed: %s", strerror(errno));
}
return;
@@ -697,7 +729,8 @@ comm_point_udp_callback(int fd, short event, void* arg)
(struct sockaddr*)&rep.addr, &rep.addrlen);
if(rcv == -1) {
#ifndef USE_WINSOCK
- if(errno != EAGAIN && errno != EINTR)
+ if(errno != EAGAIN && errno != EINTR
+ && udp_recv_needs_log(errno))
log_err("recvfrom %d failed: %s",
fd, strerror(errno));
#else
@@ -965,6 +998,10 @@ comm_point_tcp_accept_callback(int fd, short event, void* arg)
/* clear leftover flags from previous use, and then set the
* correct event base for the event structure for libevent */
ub_event_free(c_hdl->ev->ev);
+ 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;
+ else c_hdl->tcp_do_toggle_rw = 1;
if(c_hdl->type == comm_http) {
#ifdef HAVE_NGHTTP2
@@ -978,6 +1015,10 @@ comm_point_tcp_accept_callback(int fd, short event, void* arg)
log_warn("failed to submit http2 settings");
return;
}
+ if(!c->ssl) {
+ c_hdl->tcp_do_toggle_rw = 0;
+ c_hdl->use_h2 = 1;
+ }
#endif
c_hdl->ev->ev = ub_event_new(c_hdl->ev->base->eb->base, -1,
UB_EV_PERSIST | UB_EV_READ | UB_EV_TIMEOUT,
@@ -1042,6 +1083,8 @@ reclaim_tcp_handler(struct comm_point* c)
comm_point_start_listening(c->tcp_parent, -1, -1);
}
}
+ c->tcp_more_read_again = NULL;
+ c->tcp_more_write_again = NULL;
}
/** do the callback when writing is done */
@@ -1049,16 +1092,27 @@ static void
tcp_callback_writer(struct comm_point* c)
{
log_assert(c->type == comm_tcp);
- sldns_buffer_clear(c->buffer);
+ if(!c->tcp_write_and_read) {
+ sldns_buffer_clear(c->buffer);
+ c->tcp_byte_count = 0;
+ }
if(c->tcp_do_toggle_rw)
c->tcp_is_reading = 1;
- c->tcp_byte_count = 0;
/* switch from listening(write) to listening(read) */
if(c->tcp_req_info) {
tcp_req_info_handle_writedone(c->tcp_req_info);
} else {
comm_point_stop_listening(c);
- comm_point_start_listening(c, -1, c->tcp_timeout_msec);
+ if(c->tcp_write_and_read) {
+ fptr_ok(fptr_whitelist_comm_point(c->callback));
+ if( (*c->callback)(c, c->cb_arg, NETEVENT_PKT_WRITTEN,
+ &c->repinfo) ) {
+ comm_point_start_listening(c, -1,
+ c->tcp_timeout_msec);
+ }
+ } else {
+ comm_point_start_listening(c, -1, c->tcp_timeout_msec);
+ }
}
}
@@ -1361,10 +1415,28 @@ ssl_handle_write(struct comm_point* c)
}
/* ignore return, if fails we may simply block */
(void)SSL_set_mode(c->ssl, (long)SSL_MODE_ENABLE_PARTIAL_WRITE);
- if(c->tcp_byte_count < sizeof(uint16_t)) {
- uint16_t len = htons(sldns_buffer_limit(c->buffer));
+ if((c->tcp_write_and_read?c->tcp_write_byte_count:c->tcp_byte_count) < sizeof(uint16_t)) {
+ uint16_t len = htons(c->tcp_write_and_read?c->tcp_write_pkt_len:sldns_buffer_limit(c->buffer));
ERR_clear_error();
- if(sizeof(uint16_t)+sldns_buffer_remaining(c->buffer) <
+ if(c->tcp_write_and_read) {
+ if(c->tcp_write_pkt_len + 2 < LDNS_RR_BUF_SIZE) {
+ /* combine the tcp length and the query for
+ * write, this emulates writev */
+ uint8_t buf[LDNS_RR_BUF_SIZE];
+ memmove(buf, &len, sizeof(uint16_t));
+ memmove(buf+sizeof(uint16_t),
+ c->tcp_write_pkt,
+ c->tcp_write_pkt_len);
+ r = SSL_write(c->ssl,
+ (void*)(buf+c->tcp_write_byte_count),
+ c->tcp_write_pkt_len + 2 -
+ c->tcp_write_byte_count);
+ } else {
+ r = SSL_write(c->ssl,
+ (void*)(((uint8_t*)&len)+c->tcp_write_byte_count),
+ (int)(sizeof(uint16_t)-c->tcp_write_byte_count));
+ }
+ } else if(sizeof(uint16_t)+sldns_buffer_remaining(c->buffer) <
LDNS_RR_BUF_SIZE) {
/* combine the tcp length and the query for write,
* this emulates writev */
@@ -1406,20 +1478,32 @@ ssl_handle_write(struct comm_point* c)
log_crypto_err("could not SSL_write");
return 0;
}
- c->tcp_byte_count += r;
- if(c->tcp_byte_count < sizeof(uint16_t))
- return 1;
- sldns_buffer_set_position(c->buffer, c->tcp_byte_count -
- sizeof(uint16_t));
- if(sldns_buffer_remaining(c->buffer) == 0) {
+ if(c->tcp_write_and_read) {
+ c->tcp_write_byte_count += r;
+ if(c->tcp_write_byte_count < sizeof(uint16_t))
+ return 1;
+ } else {
+ c->tcp_byte_count += r;
+ if(c->tcp_byte_count < sizeof(uint16_t))
+ return 1;
+ sldns_buffer_set_position(c->buffer, c->tcp_byte_count -
+ sizeof(uint16_t));
+ }
+ if((!c->tcp_write_and_read && sldns_buffer_remaining(c->buffer) == 0) || (c->tcp_write_and_read && c->tcp_write_byte_count == c->tcp_write_pkt_len + 2)) {
tcp_callback_writer(c);
return 1;
}
}
- log_assert(sldns_buffer_remaining(c->buffer) > 0);
+ log_assert(c->tcp_write_and_read || sldns_buffer_remaining(c->buffer) > 0);
+ log_assert(!c->tcp_write_and_read || c->tcp_write_byte_count < c->tcp_write_pkt_len + 2);
ERR_clear_error();
- r = SSL_write(c->ssl, (void*)sldns_buffer_current(c->buffer),
- (int)sldns_buffer_remaining(c->buffer));
+ if(c->tcp_write_and_read) {
+ r = SSL_write(c->ssl, (void*)(c->tcp_write_pkt + c->tcp_write_byte_count - 2),
+ (int)(c->tcp_write_pkt_len + 2 - c->tcp_write_byte_count));
+ } else {
+ r = SSL_write(c->ssl, (void*)sldns_buffer_current(c->buffer),
+ (int)sldns_buffer_remaining(c->buffer));
+ }
if(r <= 0) {
int want = SSL_get_error(c->ssl, r);
if(want == SSL_ERROR_ZERO_RETURN) {
@@ -1444,9 +1528,13 @@ ssl_handle_write(struct comm_point* c)
log_crypto_err("could not SSL_write");
return 0;
}
- sldns_buffer_skip(c->buffer, (ssize_t)r);
+ if(c->tcp_write_and_read) {
+ c->tcp_write_byte_count += r;
+ } else {
+ sldns_buffer_skip(c->buffer, (ssize_t)r);
+ }
- if(sldns_buffer_remaining(c->buffer) == 0) {
+ if((!c->tcp_write_and_read && sldns_buffer_remaining(c->buffer) == 0) || (c->tcp_write_and_read && c->tcp_write_byte_count == c->tcp_write_pkt_len + 2)) {
tcp_callback_writer(c);
}
return 1;
@@ -1458,9 +1546,17 @@ ssl_handle_write(struct comm_point* c)
/** handle ssl tcp connection with dns contents */
static int
-ssl_handle_it(struct comm_point* c)
+ssl_handle_it(struct comm_point* c, int is_write)
{
- if(c->tcp_is_reading)
+ /* handle case where renegotiation wants read during write call
+ * or write during read calls */
+ if(is_write && c->ssl_shake_state == comm_ssl_shake_hs_write)
+ return ssl_handle_read(c);
+ else if(!is_write && c->ssl_shake_state == comm_ssl_shake_hs_read)
+ return ssl_handle_write(c);
+ /* handle read events for read operation and write events for a
+ * write operation */
+ else if(!is_write)
return ssl_handle_read(c);
return ssl_handle_write(c);
}
@@ -1477,8 +1573,8 @@ comm_point_tcp_handle_read(int fd, struct comm_point* c, int short_ok)
ssize_t r;
log_assert(c->type == comm_tcp || c->type == comm_local);
if(c->ssl)
- return ssl_handle_it(c);
- if(!c->tcp_is_reading)
+ return ssl_handle_it(c, 0);
+ if(!c->tcp_is_reading && !c->tcp_write_and_read)
return 0;
log_assert(fd != -1);
@@ -1581,10 +1677,10 @@ comm_point_tcp_handle_write(int fd, struct comm_point* c)
#else
buffer = c->buffer;
#endif
- if(c->tcp_is_reading && !c->ssl)
+ if(c->tcp_is_reading && !c->ssl && !c->tcp_write_and_read)
return 0;
log_assert(fd != -1);
- if(c->tcp_byte_count == 0 && c->tcp_check_nb_connect) {
+ if(((!c->tcp_write_and_read && c->tcp_byte_count == 0) || (c->tcp_write_and_read && c->tcp_write_byte_count == 0)) && c->tcp_check_nb_connect) {
/* check for pending error from nonblocking connect */
/* from Stevens, unix network programming, vol1, 3rd ed, p450*/
int error = 0;
@@ -1625,7 +1721,7 @@ comm_point_tcp_handle_write(int fd, struct comm_point* c)
}
}
if(c->ssl)
- return ssl_handle_it(c);
+ return ssl_handle_it(c, 1);
#ifdef USE_MSG_FASTOPEN
/* Only try this on first use of a connection that uses tfo,
@@ -1634,15 +1730,22 @@ comm_point_tcp_handle_write(int fd, struct comm_point* c)
if(c->tcp_do_fastopen == 1) {
/* this form of sendmsg() does both a connect() and send() so need to
look for various flavours of error*/
- uint16_t len = htons(sldns_buffer_limit(buffer));
+ uint16_t len = htons(c->tcp_write_and_read?c->tcp_write_pkt_len:sldns_buffer_limit(buffer));
struct msghdr msg;
struct iovec iov[2];
c->tcp_do_fastopen = 0;
memset(&msg, 0, sizeof(msg));
- iov[0].iov_base = (uint8_t*)&len + c->tcp_byte_count;
- iov[0].iov_len = sizeof(uint16_t) - c->tcp_byte_count;
- iov[1].iov_base = sldns_buffer_begin(buffer);
- iov[1].iov_len = sldns_buffer_limit(buffer);
+ if(c->tcp_write_and_read) {
+ iov[0].iov_base = (uint8_t*)&len + c->tcp_write_byte_count;
+ iov[0].iov_len = sizeof(uint16_t) - c->tcp_write_byte_count;
+ iov[1].iov_base = c->tcp_write_pkt;
+ iov[1].iov_len = c->tcp_write_pkt_len;
+ } else {
+ iov[0].iov_base = (uint8_t*)&len + c->tcp_byte_count;
+ iov[0].iov_len = sizeof(uint16_t) - c->tcp_byte_count;
+ iov[1].iov_base = sldns_buffer_begin(buffer);
+ iov[1].iov_len = sldns_buffer_limit(buffer);
+ }
log_assert(iov[0].iov_len > 0);
msg.msg_name = &c->repinfo.addr;
msg.msg_namelen = c->repinfo.addrlen;
@@ -1688,12 +1791,18 @@ comm_point_tcp_handle_write(int fd, struct comm_point* c)
}
} else {
- c->tcp_byte_count += r;
- if(c->tcp_byte_count < sizeof(uint16_t))
- return 1;
- sldns_buffer_set_position(buffer, c->tcp_byte_count -
- sizeof(uint16_t));
- if(sldns_buffer_remaining(buffer) == 0) {
+ if(c->tcp_write_and_read) {
+ c->tcp_write_byte_count += r;
+ if(c->tcp_write_byte_count < sizeof(uint16_t))
+ return 1;
+ } else {
+ c->tcp_byte_count += r;
+ if(c->tcp_byte_count < sizeof(uint16_t))
+ return 1;
+ sldns_buffer_set_position(buffer, c->tcp_byte_count -
+ sizeof(uint16_t));
+ }
+ if((!c->tcp_write_and_read && sldns_buffer_remaining(buffer) == 0) || (c->tcp_write_and_read && c->tcp_write_byte_count == c->tcp_write_pkt_len + 2)) {
tcp_callback_writer(c);
return 1;
}
@@ -1701,19 +1810,31 @@ comm_point_tcp_handle_write(int fd, struct comm_point* c)
}
#endif /* USE_MSG_FASTOPEN */
- if(c->tcp_byte_count < sizeof(uint16_t)) {
- uint16_t len = htons(sldns_buffer_limit(buffer));
+ if((c->tcp_write_and_read?c->tcp_write_byte_count:c->tcp_byte_count) < sizeof(uint16_t)) {
+ uint16_t len = htons(c->tcp_write_and_read?c->tcp_write_pkt_len:sldns_buffer_limit(buffer));
#ifdef HAVE_WRITEV
struct iovec iov[2];
- iov[0].iov_base = (uint8_t*)&len + c->tcp_byte_count;
- iov[0].iov_len = sizeof(uint16_t) - c->tcp_byte_count;
- iov[1].iov_base = sldns_buffer_begin(buffer);
- iov[1].iov_len = sldns_buffer_limit(buffer);
+ if(c->tcp_write_and_read) {
+ iov[0].iov_base = (uint8_t*)&len + c->tcp_write_byte_count;
+ iov[0].iov_len = sizeof(uint16_t) - c->tcp_write_byte_count;
+ iov[1].iov_base = c->tcp_write_pkt;
+ iov[1].iov_len = c->tcp_write_pkt_len;
+ } else {
+ iov[0].iov_base = (uint8_t*)&len + c->tcp_byte_count;
+ iov[0].iov_len = sizeof(uint16_t) - c->tcp_byte_count;
+ iov[1].iov_base = sldns_buffer_begin(buffer);
+ iov[1].iov_len = sldns_buffer_limit(buffer);
+ }
log_assert(iov[0].iov_len > 0);
r = writev(fd, iov, 2);
#else /* HAVE_WRITEV */
- r = send(fd, (void*)(((uint8_t*)&len)+c->tcp_byte_count),
- sizeof(uint16_t)-c->tcp_byte_count, 0);
+ if(c->tcp_write_and_read) {
+ r = send(fd, (void*)(((uint8_t*)&len)+c->tcp_write_byte_count),
+ sizeof(uint16_t)-c->tcp_write_byte_count, 0);
+ } else {
+ r = send(fd, (void*)(((uint8_t*)&len)+c->tcp_byte_count),
+ sizeof(uint16_t)-c->tcp_byte_count, 0);
+ }
#endif /* HAVE_WRITEV */
if(r == -1) {
#ifndef USE_WINSOCK
@@ -1752,19 +1873,31 @@ comm_point_tcp_handle_write(int fd, struct comm_point* c)
#endif
return 0;
}
- c->tcp_byte_count += r;
- if(c->tcp_byte_count < sizeof(uint16_t))
- return 1;
- sldns_buffer_set_position(buffer, c->tcp_byte_count -
- sizeof(uint16_t));
- if(sldns_buffer_remaining(buffer) == 0) {
+ if(c->tcp_write_and_read) {
+ c->tcp_write_byte_count += r;
+ if(c->tcp_write_byte_count < sizeof(uint16_t))
+ return 1;
+ } else {
+ c->tcp_byte_count += r;
+ if(c->tcp_byte_count < sizeof(uint16_t))
+ return 1;
+ sldns_buffer_set_position(buffer, c->tcp_byte_count -
+ sizeof(uint16_t));
+ }
+ if((!c->tcp_write_and_read && sldns_buffer_remaining(buffer) == 0) || (c->tcp_write_and_read && c->tcp_write_byte_count == c->tcp_write_pkt_len + 2)) {
tcp_callback_writer(c);
return 1;
}
}
- log_assert(sldns_buffer_remaining(buffer) > 0);
- r = send(fd, (void*)sldns_buffer_current(buffer),
- sldns_buffer_remaining(buffer), 0);
+ log_assert(c->tcp_write_and_read || sldns_buffer_remaining(buffer) > 0);
+ log_assert(!c->tcp_write_and_read || c->tcp_write_byte_count < c->tcp_write_pkt_len + 2);
+ if(c->tcp_write_and_read) {
+ r = send(fd, (void*)c->tcp_write_pkt + c->tcp_write_byte_count - 2,
+ c->tcp_write_pkt_len + 2 - c->tcp_write_byte_count, 0);
+ } else {
+ r = send(fd, (void*)sldns_buffer_current(buffer),
+ sldns_buffer_remaining(buffer), 0);
+ }
if(r == -1) {
#ifndef USE_WINSOCK
if(errno == EINTR || errno == EAGAIN)
@@ -1787,9 +1920,13 @@ comm_point_tcp_handle_write(int fd, struct comm_point* c)
&c->repinfo.addr, c->repinfo.addrlen);
return 0;
}
- sldns_buffer_skip(buffer, r);
+ if(c->tcp_write_and_read) {
+ c->tcp_write_byte_count += r;
+ } else {
+ sldns_buffer_skip(buffer, r);
+ }
- if(sldns_buffer_remaining(buffer) == 0) {
+ if((!c->tcp_write_and_read && sldns_buffer_remaining(buffer) == 0) || (c->tcp_write_and_read && c->tcp_write_byte_count == c->tcp_write_pkt_len + 2)) {
tcp_callback_writer(c);
}
@@ -1819,6 +1956,54 @@ tcp_req_info_read_again(int fd, struct comm_point* c)
}
}
+/** read again to drain buffers when there could be more to read */
+static void
+tcp_more_read_again(int fd, struct comm_point* c)
+{
+ /* if the packet is done, but another one could be waiting on
+ * the connection, the callback signals this, and we try again */
+ /* this continues until the read routines get EAGAIN or so,
+ * and thus does not call the callback, and the bool is 0 */
+ int* moreread = c->tcp_more_read_again;
+ while(moreread && *moreread) {
+ *moreread = 0;
+ if(!comm_point_tcp_handle_read(fd, c, 0)) {
+ reclaim_tcp_handler(c);
+ if(!c->tcp_do_close) {
+ fptr_ok(fptr_whitelist_comm_point(
+ c->callback));
+ (void)(*c->callback)(c, c->cb_arg,
+ NETEVENT_CLOSED, NULL);
+ }
+ return;
+ }
+ }
+}
+
+/** write again to fill up when there could be more to write */
+static void
+tcp_more_write_again(int fd, struct comm_point* c)
+{
+ /* if the packet is done, but another is waiting to be written,
+ * the callback signals it and we try again. */
+ /* this continues until the write routines get EAGAIN or so,
+ * and thus does not call the callback, and the bool is 0 */
+ int* morewrite = c->tcp_more_write_again;
+ while(morewrite && *morewrite) {
+ *morewrite = 0;
+ if(!comm_point_tcp_handle_write(fd, c)) {
+ reclaim_tcp_handler(c);
+ if(!c->tcp_do_close) {
+ fptr_ok(fptr_whitelist_comm_point(
+ c->callback));
+ (void)(*c->callback)(c, c->cb_arg,
+ NETEVENT_CLOSED, NULL);
+ }
+ return;
+ }
+ }
+}
+
void
comm_point_tcp_handle_callback(int fd, short event, void* arg)
{
@@ -1839,7 +2024,7 @@ comm_point_tcp_handle_callback(int fd, short event, void* arg)
if(!c->tcp_do_close) {
fptr_ok(fptr_whitelist_comm_point(
c->callback));
- (void)(*c->callback)(c, c->cb_arg,
+ (void)(*c->callback)(c, c->cb_arg,
NETEVENT_CLOSED, NULL);
}
return;
@@ -1857,34 +2042,46 @@ comm_point_tcp_handle_callback(int fd, short event, void* arg)
}
return;
}
- if(event&UB_EV_READ) {
+ if(event&UB_EV_READ
+#ifdef USE_MSG_FASTOPEN
+ && !(c->tcp_do_fastopen && (event&UB_EV_WRITE))
+#endif
+ ) {
int has_tcpq = (c->tcp_req_info != NULL);
+ int* moreread = c->tcp_more_read_again;
if(!comm_point_tcp_handle_read(fd, c, 0)) {
reclaim_tcp_handler(c);
if(!c->tcp_do_close) {
fptr_ok(fptr_whitelist_comm_point(
c->callback));
- (void)(*c->callback)(c, c->cb_arg,
+ (void)(*c->callback)(c, c->cb_arg,
NETEVENT_CLOSED, NULL);
}
+ return;
}
if(has_tcpq && c->tcp_req_info && c->tcp_req_info->read_again)
tcp_req_info_read_again(fd, c);
+ if(moreread && *moreread)
+ tcp_more_read_again(fd, c);
return;
}
if(event&UB_EV_WRITE) {
int has_tcpq = (c->tcp_req_info != NULL);
+ int* morewrite = c->tcp_more_write_again;
if(!comm_point_tcp_handle_write(fd, c)) {
reclaim_tcp_handler(c);
if(!c->tcp_do_close) {
fptr_ok(fptr_whitelist_comm_point(
c->callback));
- (void)(*c->callback)(c, c->cb_arg,
+ (void)(*c->callback)(c, c->cb_arg,
NETEVENT_CLOSED, NULL);
}
+ return;
}
if(has_tcpq && c->tcp_req_info && c->tcp_req_info->read_again)
tcp_req_info_read_again(fd, c);
+ if(morewrite && *morewrite)
+ tcp_more_write_again(fd, c);
return;
}
log_err("Ignored event %d for tcphdl.", event);
@@ -2359,48 +2556,76 @@ int http2_stream_close_cb(nghttp2_session* ATTR_UNUSED(session),
ssize_t http2_recv_cb(nghttp2_session* ATTR_UNUSED(session), uint8_t* buf,
size_t len, int ATTR_UNUSED(flags), void* cb_arg)
{
-#ifdef HAVE_SSL
struct http2_session* h2_session = (struct http2_session*)cb_arg;
- int r;
+ ssize_t ret;
log_assert(h2_session->c->type == comm_http);
log_assert(h2_session->c->h2_session);
- if(!h2_session->c->ssl)
- return 0;
+#ifdef HAVE_SSL
+ if(h2_session->c->ssl) {
+ int r;
+ ERR_clear_error();
+ r = SSL_read(h2_session->c->ssl, buf, len);
+ if(r <= 0) {
+ int want = SSL_get_error(h2_session->c->ssl, r);
+ if(want == SSL_ERROR_ZERO_RETURN) {
+ return NGHTTP2_ERR_EOF;
+ } else if(want == SSL_ERROR_WANT_READ) {
+ return NGHTTP2_ERR_WOULDBLOCK;
+ } else if(want == SSL_ERROR_WANT_WRITE) {
+ h2_session->c->ssl_shake_state = comm_ssl_shake_hs_write;
+ comm_point_listen_for_rw(h2_session->c, 0, 1);
+ return NGHTTP2_ERR_WOULDBLOCK;
+ } else if(want == SSL_ERROR_SYSCALL) {
+#ifdef ECONNRESET
+ if(errno == ECONNRESET && verbosity < 2)
+ return NGHTTP2_ERR_CALLBACK_FAILURE;
+#endif
+ if(errno != 0)
+ log_err("SSL_read syscall: %s",
+ strerror(errno));
+ return NGHTTP2_ERR_CALLBACK_FAILURE;
+ }
+ log_crypto_err("could not SSL_read");
+ return NGHTTP2_ERR_CALLBACK_FAILURE;
+ }
+ return r;
+ }
+#endif /* HAVE_SSL */
- ERR_clear_error();
- r = SSL_read(h2_session->c->ssl, buf, len);
- if(r <= 0) {
- int want = SSL_get_error(h2_session->c->ssl, r);
- if(want == SSL_ERROR_ZERO_RETURN) {
- return NGHTTP2_ERR_EOF;
- } else if(want == SSL_ERROR_WANT_READ) {
- return NGHTTP2_ERR_WOULDBLOCK;
- } else if(want == SSL_ERROR_WANT_WRITE) {
- h2_session->c->ssl_shake_state = comm_ssl_shake_hs_write;
- comm_point_listen_for_rw(h2_session->c, 0, 1);
+ ret = recv(h2_session->c->fd, buf, len, 0);
+ if(ret == 0) {
+ return NGHTTP2_ERR_EOF;
+ } else if(ret < 0) {
+#ifndef USE_WINSOCK
+ if(errno == EINTR || errno == EAGAIN)
return NGHTTP2_ERR_WOULDBLOCK;
- } else if(want == SSL_ERROR_SYSCALL) {
#ifdef ECONNRESET
- if(errno == ECONNRESET && verbosity < 2)
- return NGHTTP2_ERR_CALLBACK_FAILURE;
+ if(errno == ECONNRESET && verbosity < 2)
+ return NGHTTP2_ERR_CALLBACK_FAILURE;
#endif
- if(errno != 0)
- log_err("SSL_read syscall: %s",
- strerror(errno));
+ log_err_addr("could not http2 recv: %s", strerror(errno),
+ &h2_session->c->repinfo.addr,
+ h2_session->c->repinfo.addrlen);
+#else /* USE_WINSOCK */
+ if(WSAGetLastError() == WSAECONNRESET)
return NGHTTP2_ERR_CALLBACK_FAILURE;
+ if(WSAGetLastError() == WSAEINPROGRESS)
+ return NGHTTP2_ERR_WOULDBLOCK;
+ if(WSAGetLastError() == WSAEWOULDBLOCK) {
+ ub_winsock_tcp_wouldblock(h2_session->c->ev->ev,
+ UB_EV_READ);
+ return NGHTTP2_ERR_WOULDBLOCK;
}
- log_crypto_err("could not SSL_read");
+ log_err_addr("could not http2 recv: %s",
+ wsa_strerror(WSAGetLastError()),
+ &h2_session->c->repinfo.addr,
+ h2_session->c->repinfo.addrlen);
+#endif
return NGHTTP2_ERR_CALLBACK_FAILURE;
}
- return r;
-#else
- (void)buf;
- (void)len;
- (void)cb_arg;
- return -1;
-#endif
+ return ret;
}
#endif /* HAVE_NGHTTP2 */
@@ -2411,15 +2636,17 @@ comm_point_http2_handle_read(int ATTR_UNUSED(fd), struct comm_point* c)
#ifdef HAVE_NGHTTP2
int ret;
log_assert(c->h2_session);
- log_assert(c->ssl);
/* reading until recv cb returns NGHTTP2_ERR_WOULDBLOCK */
ret = nghttp2_session_recv(c->h2_session->session);
if(ret) {
if(ret != NGHTTP2_ERR_EOF &&
ret != NGHTTP2_ERR_CALLBACK_FAILURE) {
- verbose(VERB_QUERY, "http2: session_recv failed, "
- "error: %s", nghttp2_strerror(ret));
+ char a[256];
+ addr_to_str(&c->repinfo.addr, c->repinfo.addrlen,
+ a, sizeof(a));
+ verbose(VERB_QUERY, "http2: session_recv from %s failed, "
+ "error: %s", a, nghttp2_strerror(ret));
}
return 0;
}
@@ -2648,47 +2875,81 @@ http_write_more(int fd, struct comm_point* c)
ssize_t http2_send_cb(nghttp2_session* ATTR_UNUSED(session), const uint8_t* buf,
size_t len, int ATTR_UNUSED(flags), void* cb_arg)
{
-#ifdef HAVE_SSL
- int r;
+ ssize_t ret;
struct http2_session* h2_session = (struct http2_session*)cb_arg;
log_assert(h2_session->c->type == comm_http);
log_assert(h2_session->c->h2_session);
- if(!h2_session->c->ssl)
- return 0;
-
- ERR_clear_error();
- r = SSL_write(h2_session->c->ssl, buf, len);
- if(r <= 0) {
- int want = SSL_get_error(h2_session->c->ssl, r);
- if(want == SSL_ERROR_ZERO_RETURN) {
+#ifdef HAVE_SSL
+ if(h2_session->c->ssl) {
+ int r;
+ ERR_clear_error();
+ r = SSL_write(h2_session->c->ssl, buf, len);
+ if(r <= 0) {
+ int want = SSL_get_error(h2_session->c->ssl, r);
+ if(want == SSL_ERROR_ZERO_RETURN) {
+ return NGHTTP2_ERR_CALLBACK_FAILURE;
+ } else if(want == SSL_ERROR_WANT_READ) {
+ h2_session->c->ssl_shake_state = comm_ssl_shake_hs_read;
+ comm_point_listen_for_rw(h2_session->c, 1, 0);
+ return NGHTTP2_ERR_WOULDBLOCK;
+ } else if(want == SSL_ERROR_WANT_WRITE) {
+ return NGHTTP2_ERR_WOULDBLOCK;
+ } else if(want == SSL_ERROR_SYSCALL) {
+#ifdef EPIPE
+ if(errno == EPIPE && verbosity < 2)
+ return NGHTTP2_ERR_CALLBACK_FAILURE;
+#endif
+ if(errno != 0)
+ log_err("SSL_write syscall: %s",
+ strerror(errno));
+ return NGHTTP2_ERR_CALLBACK_FAILURE;
+ }
+ log_crypto_err("could not SSL_write");
return NGHTTP2_ERR_CALLBACK_FAILURE;
- } else if(want == SSL_ERROR_WANT_READ) {
- h2_session->c->ssl_shake_state = comm_ssl_shake_hs_read;
- comm_point_listen_for_rw(h2_session->c, 1, 0);
- return NGHTTP2_ERR_WOULDBLOCK;
- } else if(want == SSL_ERROR_WANT_WRITE) {
+ }
+ return r;
+ }
+#endif /* HAVE_SSL */
+
+ ret = send(h2_session->c->fd, buf, len, 0);
+ if(ret == 0) {
+ return NGHTTP2_ERR_CALLBACK_FAILURE;
+ } else if(ret < 0) {
+#ifndef USE_WINSOCK
+ if(errno == EINTR || errno == EAGAIN)
return NGHTTP2_ERR_WOULDBLOCK;
- } else if(want == SSL_ERROR_SYSCALL) {
#ifdef EPIPE
- if(errno == EPIPE && verbosity < 2)
- return NGHTTP2_ERR_CALLBACK_FAILURE;
+ if(errno == EPIPE && verbosity < 2)
+ return NGHTTP2_ERR_CALLBACK_FAILURE;
#endif
- if(errno != 0)
- log_err("SSL_write syscall: %s",
- strerror(errno));
+#ifdef ECONNRESET
+ if(errno == ECONNRESET && verbosity < 2)
return NGHTTP2_ERR_CALLBACK_FAILURE;
+#endif
+ log_err_addr("could not http2 write: %s", strerror(errno),
+ &h2_session->c->repinfo.addr,
+ h2_session->c->repinfo.addrlen);
+#else /* USE_WINSOCK */
+ if(WSAGetLastError() == WSAENOTCONN)
+ return NGHTTP2_ERR_WOULDBLOCK;
+ if(WSAGetLastError() == WSAEINPROGRESS)
+ return NGHTTP2_ERR_WOULDBLOCK;
+ if(WSAGetLastError() == WSAEWOULDBLOCK) {
+ ub_winsock_tcp_wouldblock(h2_session->c->ev->ev,
+ UB_EV_WRITE);
+ return NGHTTP2_ERR_WOULDBLOCK;
}
- log_crypto_err("could not SSL_write");
+ if(WSAGetLastError() == WSAECONNRESET && verbosity < 2)
+ return NGHTTP2_ERR_CALLBACK_FAILURE;
+ log_err_addr("could not http2 write: %s",
+ wsa_strerror(WSAGetLastError()),
+ &h2_session->c->repinfo.addr,
+ h2_session->c->repinfo.addrlen);
+#endif
return NGHTTP2_ERR_CALLBACK_FAILURE;
}
- return r;
-#else
- (void)buf;
- (void)len;
- (void)cb_arg;
- return -1;
-#endif
+ return ret;
}
#endif /* HAVE_NGHTTP2 */
@@ -2699,7 +2960,6 @@ comm_point_http2_handle_write(int ATTR_UNUSED(fd), struct comm_point* c)
#ifdef HAVE_NGHTTP2
int ret;
log_assert(c->h2_session);
- log_assert(c->ssl);
ret = nghttp2_session_send(c->h2_session->session);
if(ret) {
@@ -2811,7 +3071,7 @@ comm_point_http_handle_callback(int fd, short event, void* arg)
if(!c->tcp_do_close) {
fptr_ok(fptr_whitelist_comm_point(
c->callback));
- (void)(*c->callback)(c, c->cb_arg,
+ (void)(*c->callback)(c, c->cb_arg,
NETEVENT_CLOSED, NULL);
}
}
@@ -2823,7 +3083,7 @@ comm_point_http_handle_callback(int fd, short event, void* arg)
if(!c->tcp_do_close) {
fptr_ok(fptr_whitelist_comm_point(
c->callback));
- (void)(*c->callback)(c, c->cb_arg,
+ (void)(*c->callback)(c, c->cb_arg,
NETEVENT_CLOSED, NULL);
}
}
@@ -3555,6 +3815,7 @@ comm_point_close(struct comm_point* c)
if(!c)
return;
if(c->fd != -1) {
+ verbose(5, "comm_point_close of %d: event_del", c->fd);
if(ub_event_del(c->ev->ev) != 0) {
log_err("could not event_del on close");
}
@@ -3736,12 +3997,20 @@ comm_point_start_listening(struct comm_point* c, int newfd, int msec)
}
if(c->type == comm_tcp || c->type == comm_http) {
ub_event_del_bits(c->ev->ev, UB_EV_READ|UB_EV_WRITE);
- if(c->tcp_is_reading)
+ if(c->tcp_write_and_read) {
+ verbose(5, "startlistening %d mode rw", (newfd==-1?c->fd:newfd));
+ ub_event_add_bits(c->ev->ev, UB_EV_READ|UB_EV_WRITE);
+ } else if(c->tcp_is_reading) {
+ verbose(5, "startlistening %d mode r", (newfd==-1?c->fd:newfd));
ub_event_add_bits(c->ev->ev, UB_EV_READ);
- else ub_event_add_bits(c->ev->ev, UB_EV_WRITE);
+ } else {
+ verbose(5, "startlistening %d mode w", (newfd==-1?c->fd:newfd));
+ ub_event_add_bits(c->ev->ev, UB_EV_WRITE);
+ }
}
if(newfd != -1) {
- if(c->fd != -1) {
+ if(c->fd != -1 && c->fd != newfd) {
+ verbose(5, "cpsl close of fd %d for %d", c->fd, newfd);
sock_close(c->fd);
}
c->fd = newfd;
diff --git a/contrib/unbound/util/netevent.h b/contrib/unbound/util/netevent.h
index 6986f881b38a..daa954b6492f 100644
--- a/contrib/unbound/util/netevent.h
+++ b/contrib/unbound/util/netevent.h
@@ -95,6 +95,9 @@ typedef int comm_point_callback_type(struct comm_point*, void*, int,
#define NETEVENT_CAPSFAIL -3
/** to pass done transfer to callback function; http file is complete */
#define NETEVENT_DONE -4
+/** to pass write of the write packet is done to callback function
+ * used when tcp_write_and_read is enabled */
+#define NETEVENT_PKT_WRITTEN -5
/** timeout to slow accept calls when not possible, in msec. */
#define NETEVENT_SLOW_ACCEPT_TIME 2000
@@ -276,6 +279,44 @@ struct comm_point {
and after read/write completes. No callback is done. */
int tcp_do_close;
+ /** flag that indicates the stream is both written and read from. */
+ int tcp_write_and_read;
+
+ /** byte count for written length over write channel, for when
+ * tcp_write_and_read is enabled. When tcp_write_and_read is enabled,
+ * this is the counter for writing, the one for reading is in the
+ * commpoint.buffer sldns buffer. The counter counts from 0 to
+ * 2+tcp_write_pkt_len, and includes the tcp length bytes. */
+ size_t tcp_write_byte_count;
+
+ /** packet to write currently over the write channel. for when
+ * tcp_write_and_read is enabled. When tcp_write_and_read is enabled,
+ * this is the buffer for the written packet, the commpoint.buffer
+ * sldns buffer is the buffer for the received packet. */
+ uint8_t* tcp_write_pkt;
+ /** length of tcp_write_pkt in bytes */
+ size_t tcp_write_pkt_len;
+
+ /** if set try to read another packet again (over connection with
+ * multiple packets), once set, tries once, then zero again,
+ * so set it in the packet complete section.
+ * The pointer itself has to be set before the callback is invoked,
+ * when you set things up, and continue to exist also after the
+ * commpoint is closed and deleted in your callback. So that after
+ * the callback cleans up netevent can see what it has to do.
+ * Or leave NULL if it is not used at all. */
+ int* tcp_more_read_again;
+
+ /** if set try to write another packet (over connection with
+ * multiple packets), once set, tries once, then zero again,
+ * so set it in the packet complete section.
+ * The pointer itself has to be set before the callback is invoked,
+ * when you set things up, and continue to exist also after the
+ * commpoint is closed and deleted in your callback. So that after
+ * the callback cleans up netevent can see what it has to do.
+ * Or leave NULL if it is not used at all. */
+ int* tcp_more_write_again;
+
/** if set, read/write completes:
read/write state of tcp is toggled.
buffer reset/bytecount reset.
@@ -589,7 +630,8 @@ void comm_point_drop_reply(struct comm_reply* repinfo);
* Send an udp message over a commpoint.
* @param c: commpoint to send it from.
* @param packet: what to send.
- * @param addr: where to send it to.
+ * @param addr: where to send it to. If NULL, send is performed,
+ * for connected sockets, to the connected address.
* @param addrlen: length of addr.
* @return: false on a failure.
*/
diff --git a/contrib/unbound/util/regional.c b/contrib/unbound/util/regional.c
index ff36d0e21241..bd67ecf50af3 100644
--- a/contrib/unbound/util/regional.c
+++ b/contrib/unbound/util/regional.c
@@ -80,18 +80,39 @@ regional_init(struct regional* r)
r->total_large = 0;
}
-struct regional*
-regional_create_custom(size_t size)
+/**
+ * Create a new region, with custom first block and large-object sizes.
+ * @param size: length of first block.
+ * @param large_object_size: outside of chunk allocation threshold.
+ * @return: newly allocated regional.
+ */
+static struct regional*
+regional_create_custom_large_object(size_t size, size_t large_object_size)
{
- struct regional* r = (struct regional*)malloc(size);
+ struct regional* r;
size = ALIGN_UP(size, ALIGNMENT);
+ r = (struct regional*)malloc(size);
log_assert(sizeof(struct regional) <= size);
if(!r) return NULL;
r->first_size = size;
+ r->large_object_size = large_object_size;
regional_init(r);
return r;
}
+struct regional*
+regional_create_custom(size_t size)
+{
+ return regional_create_custom_large_object(size,
+ REGIONAL_LARGE_OBJECT_SIZE);
+}
+
+struct regional*
+regional_create_nochunk(size_t size)
+{
+ return regional_create_custom_large_object(size, 0);
+}
+
void
regional_free_all(struct regional *r)
{
@@ -134,7 +155,7 @@ regional_alloc(struct regional *r, size_t size)
malloc and ALIGN_UP */
a = ALIGN_UP(size, ALIGNMENT);
/* large objects */
- if(a > REGIONAL_LARGE_OBJECT_SIZE) {
+ if(a > r->large_object_size) {
s = malloc(ALIGNMENT + size);
if(!s) return NULL;
r->total_large += ALIGNMENT+size;
@@ -219,7 +240,7 @@ regional_log_stats(struct regional *r)
/* some basic assertions put here (non time critical code) */
log_assert(ALIGNMENT >= sizeof(char*));
log_assert(REGIONAL_CHUNK_SIZE > ALIGNMENT);
- log_assert(REGIONAL_CHUNK_SIZE-ALIGNMENT > REGIONAL_LARGE_OBJECT_SIZE);
+ log_assert(REGIONAL_CHUNK_SIZE-ALIGNMENT > r->large_object_size);
log_assert(REGIONAL_CHUNK_SIZE >= sizeof(struct regional));
/* debug print */
log_info("regional %u chunks, %u large",
diff --git a/contrib/unbound/util/regional.h b/contrib/unbound/util/regional.h
index e8b2cb8d00ca..b439897d52e0 100644
--- a/contrib/unbound/util/regional.h
+++ b/contrib/unbound/util/regional.h
@@ -74,6 +74,11 @@ struct regional
size_t available;
/** current chunk data position. */
char* data;
+ /** threshold for outside of chunk allocations */
+ size_t large_object_size;
+ /** padding for sizeof8 alignment of sizeof(struct regional)
+ * for 32bit systems */
+ size_t padding;
};
/**
@@ -88,6 +93,14 @@ struct regional* regional_create(void);
* @return: newly allocated regional.
*/
struct regional* regional_create_custom(size_t size);
+
+/**
+ * Create a new region, with custom settings, that will allocate everything
+ * outside the region chunk.
+ * @param size: length of first block.
+ * @return: newly allocated regional.
+ */
+struct regional* regional_create_nochunk(size_t size);
/**
* Free all memory associated with regional. Only keeps the first block with
diff --git a/contrib/unbound/validator/val_secalgo.c b/contrib/unbound/validator/val_secalgo.c
index 65bca8b69d6e..15cccf017b4e 100644
--- a/contrib/unbound/validator/val_secalgo.c
+++ b/contrib/unbound/validator/val_secalgo.c
@@ -990,6 +990,7 @@ static SECKEYPublicKey* nss_buf2ecdsa(unsigned char* key, size_t len, int algo)
return pk;
}
+#if defined(USE_DSA) && defined(USE_SHA1)
static SECKEYPublicKey* nss_buf2dsa(unsigned char* key, size_t len)
{
SECKEYPublicKey* pk;
@@ -1050,6 +1051,7 @@ static SECKEYPublicKey* nss_buf2dsa(unsigned char* key, size_t len)
}
return pk;
}
+#endif /* USE_DSA && USE_SHA1 */
static SECKEYPublicKey* nss_buf2rsa(unsigned char* key, size_t len)
{