Module Name:    src
Committed By:   christos
Date:           Sat Feb 17 18:31:19 UTC 2024

Modified Files:
        src/external/bsd/unbound/dist: config.guess config.sub
        src/external/bsd/unbound/dist/libunbound: unbound.h
        src/external/bsd/unbound/dist/services: authzone.c
        src/external/bsd/unbound/dist/util: netevent.c
        src/external/bsd/unbound/include: config.h
        src/external/bsd/unbound/lib/libunbound: Makefile shlib_version
Removed Files:
        src/external/bsd/unbound/dist/testcode: mini_tpkg.sh
        src/external/bsd/unbound/dist/testdata: ede_cache_snoop_noth_auth.rpl
            serve_expired_servfail.rpl subnet_prefetch_with_client_ecs.crpl
        src/external/bsd/unbound/dist/testdata/dnscrypt_cert.tdir: precheck.sh
        src/external/bsd/unbound/dist/testdata/dnscrypt_cert_chacha.tdir:
            precheck.sh
        src/external/bsd/unbound/dist/testdata/ede.tdir/bogus: clean.sh

Log Message:
merge differences between 1.16.3 and 1.19.1


To generate a diff of this commit:
cvs rdiff -u -r1.7 -r1.8 src/external/bsd/unbound/dist/config.guess
cvs rdiff -u -r1.6 -r1.7 src/external/bsd/unbound/dist/config.sub
cvs rdiff -u -r1.4 -r1.5 src/external/bsd/unbound/dist/libunbound/unbound.h
cvs rdiff -u -r1.2 -r1.3 src/external/bsd/unbound/dist/services/authzone.c
cvs rdiff -u -r1.1.1.1 -r0 \
    src/external/bsd/unbound/dist/testcode/mini_tpkg.sh
cvs rdiff -u -r1.1.1.1 -r0 \
    src/external/bsd/unbound/dist/testdata/ede_cache_snoop_noth_auth.rpl \
    src/external/bsd/unbound/dist/testdata/subnet_prefetch_with_client_ecs.crpl
cvs rdiff -u -r1.1.1.2 -r0 \
    src/external/bsd/unbound/dist/testdata/serve_expired_servfail.rpl
cvs rdiff -u -r1.1.1.1 -r0 \
    src/external/bsd/unbound/dist/testdata/dnscrypt_cert.tdir/precheck.sh
cvs rdiff -u -r1.1.1.1 -r0 \
    src/external/bsd/unbound/dist/testdata/dnscrypt_cert_chacha.tdir/precheck.sh
cvs rdiff -u -r1.1.1.1 -r0 \
    src/external/bsd/unbound/dist/testdata/ede.tdir/bogus/clean.sh
cvs rdiff -u -r1.5 -r1.6 src/external/bsd/unbound/dist/util/netevent.c
cvs rdiff -u -r1.11 -r1.12 src/external/bsd/unbound/include/config.h
cvs rdiff -u -r1.8 -r1.9 src/external/bsd/unbound/lib/libunbound/Makefile
cvs rdiff -u -r1.5 -r1.6 \
    src/external/bsd/unbound/lib/libunbound/shlib_version

Please note that diffs are not public domain; they are subject to the
copyright notices on the relevant files.

Modified files:

Index: src/external/bsd/unbound/dist/config.guess
diff -u src/external/bsd/unbound/dist/config.guess:1.7 src/external/bsd/unbound/dist/config.guess:1.8
--- src/external/bsd/unbound/dist/config.guess:1.7	Sat Sep 24 14:11:42 2022
+++ src/external/bsd/unbound/dist/config.guess	Sat Feb 17 13:31:17 2024
@@ -1,10 +1,10 @@
 #! /bin/sh
 # Attempt to guess a canonical system name.
-#   Copyright 1992-2022 Free Software Foundation, Inc.
+#   Copyright 1992-2024 Free Software Foundation, Inc.
 
 # shellcheck disable=SC2006,SC2268 # see below for rationale
 
-timestamp='2022-08-01'
+timestamp='2024-01-01'
 
 # This file is free software; you can redistribute it and/or modify it
 # under the terms of the GNU General Public License as published by
@@ -47,7 +47,7 @@ me=`echo "$0" | sed -e 's,.*/,,'`
 usage="\
 Usage: $0 [OPTION]
 
-Output the configuration name of the system \`$me' is run on.
+Output the configuration name of the system '$me' is run on.
 
 Options:
   -h, --help         print this help, then exit
@@ -60,13 +60,13 @@ version="\
 GNU config.guess ($timestamp)
 
 Originally written by Per Bothner.
-Copyright 1992-2022 Free Software Foundation, Inc.
+Copyright 1992-2024 Free Software Foundation, Inc.
 
 This is free software; see the source for copying conditions.  There is NO
 warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE."
 
 help="
-Try \`$me --help' for more information."
+Try '$me --help' for more information."
 
 # Parse command line
 while test $# -gt 0 ; do
@@ -102,8 +102,8 @@ GUESS=
 # temporary files to be created and, as you can see below, it is a
 # headache to deal with in a portable fashion.
 
-# Historically, `CC_FOR_BUILD' used to be named `HOST_CC'. We still
-# use `HOST_CC' if defined, but it is deprecated.
+# Historically, 'CC_FOR_BUILD' used to be named 'HOST_CC'. We still
+# use 'HOST_CC' if defined, but it is deprecated.
 
 # Portable tmp directory creation inspired by the Autoconf team.
 
@@ -155,6 +155,9 @@ Linux|GNU|GNU/*)
 
 	set_cc_for_build
 	cat <<-EOF > "$dummy.c"
+	#if defined(__ANDROID__)
+	LIBC=android
+	#else
 	#include <features.h>
 	#if defined(__UCLIBC__)
 	LIBC=uclibc
@@ -162,6 +165,8 @@ Linux|GNU|GNU/*)
 	LIBC=dietlibc
 	#elif defined(__GLIBC__)
 	LIBC=gnu
+	#elif defined(__LLVM_LIBC__)
+	LIBC=llvm
 	#else
 	#include <stdarg.h>
 	/* First heuristic to detect musl libc.  */
@@ -169,6 +174,7 @@ Linux|GNU|GNU/*)
 	LIBC=musl
 	#endif
 	#endif
+	#endif
 	EOF
 	cc_set_libc=`$CC_FOR_BUILD -E "$dummy.c" 2>/dev/null | grep '^LIBC' | sed 's, ,,g'`
 	eval "$cc_set_libc"
@@ -459,7 +465,7 @@ case $UNAME_MACHINE:$UNAME_SYSTEM:$UNAME
 		UNAME_RELEASE=`uname -v`
 		;;
 	esac
-	# Japanese Language versions have a version number like `4.1.3-JL'.
+	# Japanese Language versions have a version number like '4.1.3-JL'.
 	SUN_REL=`echo "$UNAME_RELEASE" | sed -e 's/-/_/'`
 	GUESS=sparc-sun-sunos$SUN_REL
 	;;
@@ -904,7 +910,7 @@ EOF
 	fi
 	;;
     *:FreeBSD:*:*)
-	UNAME_PROCESSOR=`/usr/bin/uname -p`
+	UNAME_PROCESSOR=`uname -p`
 	case $UNAME_PROCESSOR in
 	    amd64)
 		UNAME_PROCESSOR=x86_64 ;;
@@ -966,11 +972,37 @@ EOF
 	GNU_REL=`echo "$UNAME_RELEASE" | sed -e 's/[-(].*//'`
 	GUESS=$UNAME_MACHINE-unknown-$GNU_SYS$GNU_REL-$LIBC
 	;;
+    x86_64:[Mm]anagarm:*:*|i?86:[Mm]anagarm:*:*)
+	GUESS="$UNAME_MACHINE-pc-managarm-mlibc"
+	;;
+    *:[Mm]anagarm:*:*)
+	GUESS="$UNAME_MACHINE-unknown-managarm-mlibc"
+	;;
     *:Minix:*:*)
 	GUESS=$UNAME_MACHINE-unknown-minix
 	;;
     aarch64:Linux:*:*)
-	GUESS=$UNAME_MACHINE-unknown-linux-$LIBC
+	set_cc_for_build
+	CPU=$UNAME_MACHINE
+	LIBCABI=$LIBC
+	if test "$CC_FOR_BUILD" != no_compiler_found; then
+	    ABI=64
+	    sed 's/^	    //' << EOF > "$dummy.c"
+	    #ifdef __ARM_EABI__
+	    #ifdef __ARM_PCS_VFP
+	    ABI=eabihf
+	    #else
+	    ABI=eabi
+	    #endif
+	    #endif
+EOF
+	    cc_set_abi=`$CC_FOR_BUILD -E "$dummy.c" 2>/dev/null | grep '^ABI' | sed 's, ,,g'`
+	    eval "$cc_set_abi"
+	    case $ABI in
+		eabi | eabihf) CPU=armv8l; LIBCABI=$LIBC$ABI ;;
+	    esac
+	fi
+	GUESS=$CPU-unknown-linux-$LIBCABI
 	;;
     aarch64_be:Linux:*:*)
 	UNAME_MACHINE=aarch64_be
@@ -1036,6 +1068,15 @@ EOF
     k1om:Linux:*:*)
 	GUESS=$UNAME_MACHINE-unknown-linux-$LIBC
 	;;
+    kvx:Linux:*:*)
+	GUESS=$UNAME_MACHINE-unknown-linux-$LIBC
+	;;
+    kvx:cos:*:*)
+	GUESS=$UNAME_MACHINE-unknown-cos
+	;;
+    kvx:mbr:*:*)
+	GUESS=$UNAME_MACHINE-unknown-mbr
+	;;
     loongarch32:Linux:*:* | loongarch64:Linux:*:*)
 	GUESS=$UNAME_MACHINE-unknown-linux-$LIBC
 	;;
@@ -1191,7 +1232,7 @@ EOF
 	GUESS=$UNAME_MACHINE-pc-sysv4.2uw$UNAME_VERSION
 	;;
     i*86:OS/2:*:*)
-	# If we were able to find `uname', then EMX Unix compatibility
+	# If we were able to find 'uname', then EMX Unix compatibility
 	# is probably installed.
 	GUESS=$UNAME_MACHINE-pc-os2-emx
 	;;
@@ -1332,7 +1373,7 @@ EOF
 		GUESS=ns32k-sni-sysv
 	fi
 	;;
-    PENTIUM:*:4.0*:*)	# Unisys `ClearPath HMP IX 4000' SVR4/MP effort
+    PENTIUM:*:4.0*:*)	# Unisys 'ClearPath HMP IX 4000' SVR4/MP effort
 			# says <richard.m.bar...@ccmail.census.gov>
 	GUESS=i586-unisys-sysv4
 	;;
@@ -1554,6 +1595,9 @@ EOF
     *:Unleashed:*:*)
 	GUESS=$UNAME_MACHINE-unknown-unleashed$UNAME_RELEASE
 	;;
+    *:Ironclad:*:*)
+	GUESS=$UNAME_MACHINE-unknown-ironclad
+	;;
 esac
 
 # Do we have a guess based on uname results?

Index: src/external/bsd/unbound/dist/config.sub
diff -u src/external/bsd/unbound/dist/config.sub:1.6 src/external/bsd/unbound/dist/config.sub:1.7
--- src/external/bsd/unbound/dist/config.sub:1.6	Sat Sep 24 14:11:42 2022
+++ src/external/bsd/unbound/dist/config.sub	Sat Feb 17 13:31:17 2024
@@ -1,10 +1,10 @@
 #! /bin/sh
 # Configuration validation subroutine script.
-#   Copyright 1992-2022 Free Software Foundation, Inc.
+#   Copyright 1992-2024 Free Software Foundation, Inc.
 
 # shellcheck disable=SC2006,SC2268 # see below for rationale
 
-timestamp='2022-08-01'
+timestamp='2024-01-01'
 
 # This file is free software; you can redistribute it and/or modify it
 # under the terms of the GNU General Public License as published by
@@ -76,13 +76,13 @@ Report bugs and patches to <config-patch
 version="\
 GNU config.sub ($timestamp)
 
-Copyright 1992-2022 Free Software Foundation, Inc.
+Copyright 1992-2024 Free Software Foundation, Inc.
 
 This is free software; see the source for copying conditions.  There is NO
 warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE."
 
 help="
-Try \`$me --help' for more information."
+Try '$me --help' for more information."
 
 # Parse command line
 while test $# -gt 0 ; do
@@ -130,7 +130,7 @@ IFS=$saved_IFS
 # Separate into logical components for further validation
 case $1 in
 	*-*-*-*-*)
-		echo Invalid configuration \`"$1"\': more than four components >&2
+		echo "Invalid configuration '$1': more than four components" >&2
 		exit 1
 		;;
 	*-*-*-*)
@@ -145,7 +145,8 @@ case $1 in
 			nto-qnx* | linux-* | uclinux-uclibc* \
 			| uclinux-gnu* | kfreebsd*-gnu* | knetbsd*-gnu* | netbsd*-gnu* \
 			| netbsd*-eabi* | kopensolaris*-gnu* | cloudabi*-eabi* \
-			| storm-chaos* | os2-emx* | rtmk-nova*)
+			| storm-chaos* | os2-emx* | rtmk-nova* | managarm-* \
+			| windows-* )
 				basic_machine=$field1
 				basic_os=$maybe_os
 				;;
@@ -943,7 +944,7 @@ $basic_machine
 EOF
 		IFS=$saved_IFS
 		;;
-	# We use `pc' rather than `unknown'
+	# We use 'pc' rather than 'unknown'
 	# because (1) that's what they normally are, and
 	# (2) the word "unknown" tends to confuse beginning users.
 	i*86 | x86_64)
@@ -1075,7 +1076,7 @@ case $cpu-$vendor in
 	pentium-* | p5-* | k5-* | k6-* | nexgen-* | viac3-*)
 		cpu=i586
 		;;
-	pentiumpro-* | p6-* | 6x86-* | athlon-* | athalon_*-*)
+	pentiumpro-* | p6-* | 6x86-* | athlon-* | athlon_*-*)
 		cpu=i686
 		;;
 	pentiumii-* | pentium2-* | pentiumiii-* | pentium3-*)
@@ -1180,7 +1181,7 @@ case $cpu-$vendor in
 		case $cpu in
 			1750a | 580 \
 			| a29k \
-			| aarch64 | aarch64_be \
+			| aarch64 | aarch64_be | aarch64c | arm64ec \
 			| abacus \
 			| alpha | alphaev[4-8] | alphaev56 | alphaev6[78] \
 			| alpha64 | alpha64ev[4-8] | alpha64ev56 | alpha64ev6[78] \
@@ -1199,12 +1200,14 @@ case $cpu-$vendor in
 			| d10v | d30v | dlx | dsp16xx \
 			| e2k | elxsi | epiphany \
 			| f30[01] | f700 | fido | fr30 | frv | ft32 | fx80 \
+			| javascript \
 			| h8300 | h8500 \
 			| hppa | hppa1.[01] | hppa2.0 | hppa2.0[nw] | hppa64 \
 			| hexagon \
 			| i370 | i*86 | i860 | i960 | ia16 | ia64 \
 			| ip2k | iq2000 \
 			| k1om \
+			| kvx \
 			| le32 | le64 \
 			| lm32 \
 			| loongarch32 | loongarch64 \
@@ -1213,36 +1216,13 @@ case $cpu-$vendor in
 			| m6811 | m68hc11 | m6812 | m68hc12 | m68hcs12x \
 			| m88110 | m88k | maxq | mb | mcore | mep | metag \
 			| microblaze | microblazeel \
-			| mips | mipsbe | mipseb | mipsel | mipsle \
-			| mips16 \
-			| mips64 | mips64eb | mips64el \
-			| mips64octeon | mips64octeonel \
-			| mips64orion | mips64orionel \
-			| mips64r5900 | mips64r5900el \
-			| mips64vr | mips64vrel \
-			| mips64vr4100 | mips64vr4100el \
-			| mips64vr4300 | mips64vr4300el \
-			| mips64vr5000 | mips64vr5000el \
-			| mips64vr5900 | mips64vr5900el \
-			| mipsisa32 | mipsisa32el \
-			| mipsisa32r2 | mipsisa32r2el \
-			| mipsisa32r3 | mipsisa32r3el \
-			| mipsisa32r5 | mipsisa32r5el \
-			| mipsisa32r6 | mipsisa32r6el \
-			| mipsisa64 | mipsisa64el \
-			| mipsisa64r2 | mipsisa64r2el \
-			| mipsisa64r3 | mipsisa64r3el \
-			| mipsisa64r5 | mipsisa64r5el \
-			| mipsisa64r6 | mipsisa64r6el \
-			| mipsisa64sb1 | mipsisa64sb1el \
-			| mipsisa64sr71k | mipsisa64sr71kel \
-			| mipsr5900 | mipsr5900el \
-			| mipstx39 | mipstx39el \
+			| mips* \
 			| mmix \
 			| mn10200 | mn10300 \
 			| moxie \
 			| mt \
 			| msp430 \
+			| nanomips* \
 			| nds32 | nds32le | nds32be \
 			| nfp \
 			| nios | nios2 | nios2eb | nios2el \
@@ -1274,6 +1254,7 @@ case $cpu-$vendor in
 			| ubicom32 \
 			| v70 | v850 | v850e | v850e1 | v850es | v850e2 | v850e2v3 \
 			| vax \
+			| vc4 \
 			| visium \
 			| w65 \
 			| wasm32 | wasm64 \
@@ -1285,7 +1266,7 @@ case $cpu-$vendor in
 				;;
 
 			*)
-				echo Invalid configuration \`"$1"\': machine \`"$cpu-$vendor"\' not recognized 1>&2
+				echo "Invalid configuration '$1': machine '$cpu-$vendor' not recognized" 1>&2
 				exit 1
 				;;
 		esac
@@ -1306,11 +1287,12 @@ esac
 
 # Decode manufacturer-specific aliases for certain operating systems.
 
-if test x$basic_os != x
+if test x"$basic_os" != x
 then
 
 # First recognize some ad-hoc cases, or perhaps split kernel-os, or else just
 # set os.
+obj=
 case $basic_os in
 	gnu/linux*)
 		kernel=linux
@@ -1341,6 +1323,10 @@ EOF
 		kernel=linux
 		os=`echo "$basic_os" | sed -e 's|linux|gnu|'`
 		;;
+	managarm*)
+		kernel=managarm
+		os=`echo "$basic_os" | sed -e 's|managarm|mlibc|'`
+		;;
 	*)
 		kernel=
 		os=$basic_os
@@ -1506,10 +1492,16 @@ case $os in
 			os=eabi
 			;;
 		    *)
-			os=elf
+			os=
+			obj=elf
 			;;
 		esac
 		;;
+	aout* | coff* | elf* | pe*)
+		# These are machine code file formats, not OSes
+		obj=$os
+		os=
+		;;
 	*)
 		# No normalization, but not necessarily accepted, that comes below.
 		;;
@@ -1528,12 +1520,15 @@ else
 # system, and we'll never get to this point.
 
 kernel=
+obj=
 case $cpu-$vendor in
 	score-*)
-		os=elf
+		os=
+		obj=elf
 		;;
 	spu-*)
-		os=elf
+		os=
+		obj=elf
 		;;
 	*-acorn)
 		os=riscix1.2
@@ -1543,28 +1538,35 @@ case $cpu-$vendor in
 		os=gnu
 		;;
 	arm*-semi)
-		os=aout
+		os=
+		obj=aout
 		;;
 	c4x-* | tic4x-*)
-		os=coff
+		os=
+		obj=coff
 		;;
 	c8051-*)
-		os=elf
+		os=
+		obj=elf
 		;;
 	clipper-intergraph)
 		os=clix
 		;;
 	hexagon-*)
-		os=elf
+		os=
+		obj=elf
 		;;
 	tic54x-*)
-		os=coff
+		os=
+		obj=coff
 		;;
 	tic55x-*)
-		os=coff
+		os=
+		obj=coff
 		;;
 	tic6x-*)
-		os=coff
+		os=
+		obj=coff
 		;;
 	# This must come before the *-dec entry.
 	pdp10-*)
@@ -1586,19 +1588,24 @@ case $cpu-$vendor in
 		os=sunos3
 		;;
 	m68*-cisco)
-		os=aout
+		os=
+		obj=aout
 		;;
 	mep-*)
-		os=elf
+		os=
+		obj=elf
 		;;
 	mips*-cisco)
-		os=elf
+		os=
+		obj=elf
 		;;
-	mips*-*)
-		os=elf
+	mips*-*|nanomips*-*)
+		os=
+		obj=elf
 		;;
 	or32-*)
-		os=coff
+		os=
+		obj=coff
 		;;
 	*-tti)	# must be before sparc entry or we get the wrong os.
 		os=sysv3
@@ -1607,7 +1614,8 @@ case $cpu-$vendor in
 		os=sunos4.1.1
 		;;
 	pru-*)
-		os=elf
+		os=
+		obj=elf
 		;;
 	*-be)
 		os=beos
@@ -1688,10 +1696,12 @@ case $cpu-$vendor in
 		os=uxpv
 		;;
 	*-rom68k)
-		os=coff
+		os=
+		obj=coff
 		;;
 	*-*bug)
-		os=coff
+		os=
+		obj=coff
 		;;
 	*-apple)
 		os=macos
@@ -1709,10 +1719,11 @@ esac
 
 fi
 
-# Now, validate our (potentially fixed-up) OS.
+# Now, validate our (potentially fixed-up) individual pieces (OS, OBJ).
+
 case $os in
 	# Sometimes we do "kernel-libc", so those need to count as OSes.
-	musl* | newlib* | relibc* | uclibc*)
+	llvm* | musl* | newlib* | relibc* | uclibc*)
 		;;
 	# Likewise for "kernel-abi"
 	eabi* | gnueabi*)
@@ -1720,6 +1731,9 @@ case $os in
 	# VxWorks passes extra cpu info in the 4th filed.
 	simlinux | simwindows | spe)
 		;;
+	# See `case $cpu-$os` validation below
+	ghcjs)
+		;;
 	# Now accept the basic system types.
 	# The portable systems comes first.
 	# Each alternative MUST end in a * to match a version number.
@@ -1728,7 +1742,7 @@ case $os in
 	     | hpux* | unos* | osf* | luna* | dgux* | auroraux* | solaris* \
 	     | sym* |  plan9* | psp* | sim* | xray* | os68k* | v88r* \
 	     | hiux* | abug | nacl* | netware* | windows* \
-	     | os9* | macos* | osx* | ios* \
+	     | os9* | macos* | osx* | ios* | tvos* | watchos* \
 	     | mpw* | magic* | mmixware* | mon960* | lnews* \
 	     | amigaos* | amigados* | msdos* | newsos* | unicos* | aof* \
 	     | aos* | aros* | cloudabi* | sortix* | twizzler* \
@@ -1737,11 +1751,11 @@ case $os in
 	     | mirbsd* | netbsd* | dicos* | openedition* | ose* \
 	     | bitrig* | openbsd* | secbsd* | solidbsd* | libertybsd* | os108* \
 	     | ekkobsd* | freebsd* | riscix* | lynxos* | os400* \
-	     | bosx* | nextstep* | cxux* | aout* | elf* | oabi* \
-	     | ptx* | coff* | ecoff* | winnt* | domain* | vsta* \
+	     | bosx* | nextstep* | cxux* | oabi* \
+	     | ptx* | ecoff* | winnt* | domain* | vsta* \
 	     | udi* | lites* | ieee* | go32* | aux* | hcos* \
 	     | chorusrdb* | cegcc* | glidix* | serenity* \
-	     | cygwin* | msys* | pe* | moss* | proelf* | rtems* \
+	     | cygwin* | msys* | moss* | proelf* | rtems* \
 	     | midipix* | mingw32* | mingw64* | mint* \
 	     | uxpv* | beos* | mpeix* | udk* | moxiebox* \
 	     | interix* | uwin* | mks* | rhapsody* | darwin* \
@@ -1754,49 +1768,116 @@ case $os in
 	     | onefs* | tirtos* | phoenix* | fuchsia* | redox* | bme* \
 	     | midnightbsd* | amdhsa* | unleashed* | emscripten* | wasi* \
 	     | nsk* | powerunix* | genode* | zvmoe* | qnx* | emx* | zephyr* \
-	     | fiwix* )
+	     | fiwix* | mlibc* | cos* | mbr* | ironclad* )
 		;;
 	# This one is extra strict with allowed versions
 	sco3.2v2 | sco3.2v[4-9]* | sco5v6*)
 		# Don't forget version if it is 3.2v4 or newer.
 		;;
+	# This refers to builds using the UEFI calling convention
+	# (which depends on the architecture) and PE file format.
+	# Note that this is both a different calling convention and
+	# different file format than that of GNU-EFI
+	# (x86_64-w64-mingw32).
+	uefi)
+		;;
 	none)
 		;;
+	kernel* | msvc* )
+		# Restricted further below
+		;;
+	'')
+		if test x"$obj" = x
+		then
+			echo "Invalid configuration '$1': Blank OS only allowed with explicit machine code file format" 1>&2
+		fi
+		;;
 	*)
-		echo Invalid configuration \`"$1"\': OS \`"$os"\' not recognized 1>&2
+		echo "Invalid configuration '$1': OS '$os' not recognized" 1>&2
+		exit 1
+		;;
+esac
+
+case $obj in
+	aout* | coff* | elf* | pe*)
+		;;
+	'')
+		# empty is fine
+		;;
+	*)
+		echo "Invalid configuration '$1': Machine code format '$obj' not recognized" 1>&2
+		exit 1
+		;;
+esac
+
+# Here we handle the constraint that a (synthetic) cpu and os are
+# valid only in combination with each other and nowhere else.
+case $cpu-$os in
+	# The "javascript-unknown-ghcjs" triple is used by GHC; we
+	# accept it here in order to tolerate that, but reject any
+	# variations.
+	javascript-ghcjs)
+		;;
+	javascript-* | *-ghcjs)
+		echo "Invalid configuration '$1': cpu '$cpu' is not valid with os '$os$obj'" 1>&2
 		exit 1
 		;;
 esac
 
 # As a final step for OS-related things, validate the OS-kernel combination
 # (given a valid OS), if there is a kernel.
-case $kernel-$os in
-	linux-gnu* | linux-dietlibc* | linux-android* | linux-newlib* \
-		   | linux-musl* | linux-relibc* | linux-uclibc* )
+case $kernel-$os-$obj in
+	linux-gnu*- | linux-android*- | linux-dietlibc*- | linux-llvm*- \
+		    | linux-mlibc*- | linux-musl*- | linux-newlib*- \
+		    | linux-relibc*- | linux-uclibc*- )
+		;;
+	uclinux-uclibc*- )
+		;;
+	managarm-mlibc*- | managarm-kernel*- )
 		;;
-	uclinux-uclibc* )
+	windows*-msvc*-)
 		;;
-	-dietlibc* | -newlib* | -musl* | -relibc* | -uclibc* )
+	-dietlibc*- | -llvm*- | -mlibc*- | -musl*- | -newlib*- | -relibc*- \
+		    | -uclibc*- )
 		# These are just libc implementations, not actual OSes, and thus
 		# require a kernel.
-		echo "Invalid configuration \`$1': libc \`$os' needs explicit kernel." 1>&2
+		echo "Invalid configuration '$1': libc '$os' needs explicit kernel." 1>&2
 		exit 1
 		;;
-	kfreebsd*-gnu* | kopensolaris*-gnu*)
+	-kernel*- )
+		echo "Invalid configuration '$1': '$os' needs explicit kernel." 1>&2
+		exit 1
 		;;
-	vxworks-simlinux | vxworks-simwindows | vxworks-spe)
+	*-kernel*- )
+		echo "Invalid configuration '$1': '$kernel' does not support '$os'." 1>&2
+		exit 1
 		;;
-	nto-qnx*)
+	*-msvc*- )
+		echo "Invalid configuration '$1': '$os' needs 'windows'." 1>&2
+		exit 1
 		;;
-	os2-emx)
+	kfreebsd*-gnu*- | kopensolaris*-gnu*-)
+		;;
+	vxworks-simlinux- | vxworks-simwindows- | vxworks-spe-)
+		;;
+	nto-qnx*-)
+		;;
+	os2-emx-)
 		;;
-	*-eabi* | *-gnueabi*)
+	*-eabi*- | *-gnueabi*-)
 		;;
-	-*)
+	none--*)
+		# None (no kernel, i.e. freestanding / bare metal),
+		# can be paired with an machine code file format
+		;;
+	-*-)
 		# Blank kernel with real OS is always fine.
 		;;
-	*-*)
-		echo "Invalid configuration \`$1': Kernel \`$kernel' not known to work with OS \`$os'." 1>&2
+	--*)
+		# Blank kernel and OS with real machine code file format is always fine.
+		;;
+	*-*-*)
+		echo "Invalid configuration '$1': Kernel '$kernel' not known to work with OS '$os'." 1>&2
 		exit 1
 		;;
 esac
@@ -1879,7 +1960,7 @@ case $vendor in
 		;;
 esac
 
-echo "$cpu-$vendor-${kernel:+$kernel-}$os"
+echo "$cpu-$vendor${kernel:+-$kernel}${os:+-$os}${obj:+-$obj}"
 exit
 
 # Local variables:

Index: src/external/bsd/unbound/dist/libunbound/unbound.h
diff -u src/external/bsd/unbound/dist/libunbound/unbound.h:1.4 src/external/bsd/unbound/dist/libunbound/unbound.h:1.5
--- src/external/bsd/unbound/dist/libunbound/unbound.h:1.4	Sat Sep 24 14:11:43 2022
+++ src/external/bsd/unbound/dist/libunbound/unbound.h	Sat Feb 17 13:31:17 2024
@@ -4,22 +4,22 @@
  * Copyright (c) 2007, NLnet Labs. All rights reserved.
  *
  * This software is open source.
- * 
+ *
  * Redistribution and use in source and binary forms, with or without
  * modification, are permitted provided that the following conditions
  * are met:
- * 
+ *
  * Redistributions of source code must retain the above copyright notice,
  * this list of conditions and the following disclaimer.
- * 
+ *
  * Redistributions in binary form must reproduce the above copyright notice,
  * this list of conditions and the following disclaimer in the documentation
  * and/or other materials provided with the distribution.
- * 
+ *
  * Neither the name of the NLNET LABS nor the names of its contributors may
  * be used to endorse or promote products derived from this software without
  * specific prior written permission.
- * 
+ *
  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
  * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
  * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
@@ -36,7 +36,7 @@
 /**
  * \file
  *
- * This file contains functions to resolve DNS queries and 
+ * This file contains functions to resolve DNS queries and
  * validate the answers. Synchronously and asynchronously.
  *
  * Several ways to use this interface from an application wishing
@@ -65,7 +65,7 @@
  *	... or process() calls my_callback() with results.
  *
  *      ... if the application has nothing more to do, wait for answer
- *      ub_wait(ctx); 
+ *      ub_wait(ctx);
  *
  * Application threaded. Blocking.
  *	Blocking, same as above. The current thread does the work.
@@ -83,7 +83,7 @@
  * CRYPTO_set_id_callback and CRYPTO_set_locking_callback.
  *
  * If no threading is compiled in, the above async example uses fork(2) to
- * create a process to perform the work. The forked process exits when the 
+ * create a process to perform the work. The forked process exits when the
  * calling process exits, or ctx_delete() is called.
  * Otherwise, for asynchronous with threading, a worker thread is created.
  *
@@ -94,8 +94,8 @@
  * The second calls another worker thread (or process) to perform the work.
  * And no buffers need to be set up, but a context-switch happens.
  */
-#ifndef _UB_UNBOUND_H
-#define _UB_UNBOUND_H
+#ifndef UB_UNBOUND_H
+#define UB_UNBOUND_H
 
 #ifdef __cplusplus
 extern "C" {
@@ -128,10 +128,10 @@ struct ub_result {
 	/** the class asked for */
 	int qclass;
 
-	/** 
-	 * a list of network order DNS rdata items, terminated with a 
+	/**
+	 * a list of network order DNS rdata items, terminated with a
 	 * NULL pointer, so that data[0] is the first result entry,
-	 * data[1] the second, and the last entry is NULL. 
+	 * data[1] the second, and the last entry is NULL.
 	 * If there was no data, data[0] is NULL.
 	 */
 	char** data;
@@ -139,8 +139,8 @@ struct ub_result {
 	/** the length in bytes of the data items, len[i] for data[i] */
 	int* len;
 
-	/** 
-	 * canonical name for the result (the final cname). 
+	/**
+	 * canonical name for the result (the final cname).
 	 * zero terminated string.
 	 * May be NULL if no canonical name exists.
 	 */
@@ -165,9 +165,9 @@ struct ub_result {
 	 */
 	int havedata;
 
-	/** 
+	/**
 	 * If there was no data, and the domain did not exist, this is true.
-	 * If it is false, and there was no data, then the domain name 
+	 * If it is false, and there was no data, then the domain name
 	 * is purported to exist, but the requested data type is not available.
 	 */
 	int nxdomain;
@@ -182,19 +182,19 @@ struct ub_result {
 	 */
 	int secure;
 
-	/** 
-	 * If the result was not secure (secure==0), and this result is due 
+	/**
+	 * If the result was not secure (secure==0), and this result is due
 	 * to a security failure, bogus is true.
 	 * This means the data has been actively tampered with, signatures
-	 * failed, expected signatures were not present, timestamps on 
+	 * failed, expected signatures were not present, timestamps on
 	 * signatures were out of date and so on.
 	 *
-	 * If !secure and !bogus, this can happen if the data is not secure 
-	 * because security is disabled for that domain name. 
+	 * If !secure and !bogus, this can happen if the data is not secure
+	 * because security is disabled for that domain name.
 	 * This means the data is from a domain where data is not signed.
 	 */
 	int bogus;
-	
+
 	/**
 	 * If the result is bogus this contains a string (zero terminated)
 	 * that describes the failure.  There may be other errors as well
@@ -222,7 +222,7 @@ struct ub_result {
  * The readable function definition looks like:
  * void my_callback(void* my_arg, int err, struct ub_result* result);
  * It is called with
- *	void* my_arg: your pointer to a (struct of) data of your choice, 
+ *	void* my_arg: your pointer to a (struct of) data of your choice,
  *		or NULL.
  *	int err: if 0 all is OK, otherwise an error occurred and no results
  *	     are forthcoming.
@@ -301,8 +301,8 @@ int ub_ctx_set_option(struct ub_ctx* ctx
  * 	This is a power-users interface that lets you specify all sorts
  * 	of options.
  * @param str: the string is malloced and returned here. NULL on error.
- * 	The caller must free() the string.  In cases with multiple 
- * 	entries (auto-trust-anchor-file), a newline delimited list is 
+ * 	The caller must free() the string.  In cases with multiple
+ * 	entries (auto-trust-anchor-file), a newline delimited list is
  * 	returned in the string.
  * @return 0 if OK else an error code (malloc failure, syntax error).
  */
@@ -321,10 +321,10 @@ int ub_ctx_get_option(struct ub_ctx* ctx
 int ub_ctx_config(struct ub_ctx* ctx, const char* fname);
 
 /**
- * Set machine to forward DNS queries to, the caching resolver to use. 
- * IP4 or IP6 address. Forwards all DNS requests to that machine, which 
- * is expected to run a recursive resolver. If the proxy is not 
- * DNSSEC-capable, validation may fail. Can be called several times, in 
+ * Set machine to forward DNS queries to, the caching resolver to use.
+ * IP4 or IP6 address. Forwards all DNS requests to that machine, which
+ * is expected to run a recursive resolver. If the proxy is not
+ * DNSSEC-capable, validation may fail. Can be called several times, in
  * that case the addresses are used as backup servers.
  *
  * To read the list of nameservers from /etc/resolv.conf (from DHCP or so),
@@ -389,7 +389,7 @@ int ub_ctx_resolvconf(struct ub_ctx* ctx
 
 /**
  * Read list of hosts from the filename given.
- * Usually "/etc/hosts". 
+ * Usually "/etc/hosts".
  * These addresses are not flagged as DNSSEC secure when queried for.
  *
  * @param ctx: context.
@@ -403,7 +403,7 @@ int ub_ctx_hosts(struct ub_ctx* ctx, con
 /**
  * Add a trust anchor to the given context.
  * The trust anchor is a string, on one line, that holds a valid DNSKEY or
- * DS RR. 
+ * DS RR.
  * @param ctx: context.
  *	At this time it is only possible to add trusted keys before the
  *	first resolve is done.
@@ -465,7 +465,7 @@ int ub_ctx_debugout(struct ub_ctx* ctx, 
  * Set debug verbosity for the context
  * Output is directed to stderr.
  * @param ctx: context.
- * @param d: debug level, 0 is off, 1 is very minimal, 2 is detailed, 
+ * @param d: debug level, 0 is off, 1 is very minimal, 2 is detailed,
  *	and 3 is lots.
  * @return 0 if OK, else error.
  */
@@ -474,10 +474,10 @@ int ub_ctx_debuglevel(struct ub_ctx* ctx
 /**
  * Set a context behaviour for asynchronous action.
  * @param ctx: context.
- * @param dothread: if true, enables threading and a call to resolve_async() 
+ * @param dothread: if true, enables threading and a call to resolve_async()
  *	creates a thread to handle work in the background.
  *	If false, a process is forked to handle work in the background.
- *	Changes to this setting after async() calls have been made have 
+ *	Changes to this setting after async() calls have been made have
  *	no effect (delete and re-create the context to change).
  * @return 0 if OK, else error.
  */
@@ -495,7 +495,7 @@ int ub_poll(struct ub_ctx* ctx);
 
 /**
  * Wait for a context to finish with results. Calls ub_process() after
- * the wait for you. After the wait, there are no more outstanding 
+ * the wait for you. After the wait, there are no more outstanding
  * asynchronous queries.
  * @param ctx: context.
  * @return: 0 if OK, else error.
@@ -530,11 +530,11 @@ int ub_process(struct ub_ctx* ctx);
  * @param rrtype: type of RR in host order, 1 is A (address).
  * @param rrclass: class of RR in host order, 1 is IN (for internet).
  * @param result: the result data is returned in a newly allocated result
- * 	structure. May be NULL on return, return value is set to an error 
+ * 	structure. May be NULL on return, return value is set to an error
  * 	in that case (out of memory).
  * @return 0 if OK, else error.
  */
-int ub_resolve(struct ub_ctx* ctx, const char* name, int rrtype, 
+int ub_resolve(struct ub_ctx* ctx, const char* name, int rrtype,
 	int rrclass, struct ub_result** result);
 
 /**
@@ -561,11 +561,11 @@ int ub_resolve(struct ub_ctx* ctx, const
  * 	If an error happens during processing, your callback will be called
  * 	with error set to a nonzero value (and result==NULL).
  * @param async_id: if you pass a non-NULL value, an identifier number is
- *	returned for the query as it is in progress. It can be used to 
+ *	returned for the query as it is in progress. It can be used to
  *	cancel the query.
  * @return 0 if OK, else error.
  */
-int ub_resolve_async(struct ub_ctx* ctx, const char* name, int rrtype, 
+int ub_resolve_async(struct ub_ctx* ctx, const char* name, int rrtype,
 	int rrclass, void* mydata, ub_callback_type callback, int* async_id);
 
 /**
@@ -589,7 +589,7 @@ int ub_cancel(struct ub_ctx* ctx, int as
  */
 void ub_resolve_free(struct ub_result* result);
 
-/** 
+/**
  * Convert error value to a human readable string.
  * @param err: error code from one of the libunbound functions.
  * 	The error codes are from the type enum ub_ctx_err.
@@ -605,7 +605,7 @@ const char* ub_strerror(int err);
 int ub_ctx_print_local_zones(struct ub_ctx* ctx);
 
 /**
- * Add a new zone with the zonetype to the local authority info of the 
+ * Add a new zone with the zonetype to the local authority info of the
  * library.
  * @param ctx: context.  Is finalized by the routine.
  * @param zone_name: name of the zone in text, "example.com"
@@ -613,7 +613,7 @@ int ub_ctx_print_local_zones(struct ub_c
  * @param zone_type: type of the zone (like for unbound.conf) in text.
  * @return 0 if OK, else error.
  */
-int ub_ctx_zone_add(struct ub_ctx* ctx, const char *zone_name, 
+int ub_ctx_zone_add(struct ub_ctx* ctx, const char *zone_name,
 	const char *zone_type);
 
 /**
@@ -649,7 +649,7 @@ int ub_ctx_data_remove(struct ub_ctx* ct
  */
 const char* ub_version(void);
 
-/** 
+/**
  * Some global statistics that are not in struct stats_info,
  * this struct is shared on a shm segment (shm-key in unbound.conf)
  */
@@ -695,13 +695,22 @@ struct ub_server_stats {
 	long long num_queries;
 	/** number of queries that have been dropped/ratelimited by ip. */
 	long long num_queries_ip_ratelimited;
+	/** number of queries with a valid DNS Cookie. */
+	long long num_queries_cookie_valid;
+	/** number of queries with only the client part of the DNS Cookie. */
+	long long num_queries_cookie_client;
+	/** number of queries with invalid DNS Cookie. */
+	long long num_queries_cookie_invalid;
 	/** number of queries that had a cache-miss. */
 	long long num_queries_missed_cache;
 	/** number of prefetch queries - cachehits with prefetch */
 	long long num_queries_prefetch;
-
+	/** number of queries which are too late to process */
+	long long num_queries_timed_out;
+	/** the longest wait time in the queue */
+	long long max_query_time_us;
 	/**
-	 * Sum of the querylistsize of the worker for 
+	 * Sum of the querylistsize of the worker for
 	 * every query that missed cache. To calculate average.
 	 */
 	long long sum_query_list_size;
@@ -773,12 +782,12 @@ struct ub_server_stats {
 	long long tcp_accept_usage;
 	/** expired answers served from cache */
 	long long ans_expired;
-	/** histogram data exported to array 
+	/** histogram data exported to array
 	 * if the array is the same size, no data is lost, and
 	 * if all histograms are same size (is so by default) then
 	 * adding up works well. */
 	long long hist[UB_STATS_BUCKET_NUM];
-	
+
 	/** number of message cache entries */
 	long long msg_cache_count;
 	/** number of rrset cache entries */
@@ -788,6 +797,11 @@ struct ub_server_stats {
 	/** number of key cache entries */
 	long long key_cache_count;
 
+	/** maximum number of collisions in the msg cache */
+	long long msg_cache_max_collisions;
+	/** maximum number of collisions in the rrset cache */
+	long long rrset_cache_max_collisions;
+
 	/** number of queries that used dnscrypt */
 	long long num_query_dnscrypt_crypted;
 	/** number of queries that queried dnscrypt certificates */
@@ -819,6 +833,8 @@ struct ub_server_stats {
 	/** number of queries answered from edns-subnet specific data, and
 	 * the answer was from the edns-subnet cache. */
 	long long num_query_subnet_cache;
+	/** number of queries served from cachedb */
+	long long num_query_cachedb;
 	/** number of bytes in the stream wait buffers */
 	long long mem_stream_wait;
 	/** number of bytes in the HTTP2 query buffers */
@@ -831,7 +847,7 @@ struct ub_server_stats {
 	long long rpz_action[UB_STATS_RPZ_ACTION_NUM];
 };
 
-/** 
+/**
  * Statistics to send over the control pipe when asked
  * This struct is made to be memcopied, sent in binary.
  * shm mapped with (number+1) at num_threads+1, with first as total
@@ -860,4 +876,4 @@ struct ub_stats_info {
 }
 #endif
 
-#endif /* _UB_UNBOUND_H */
+#endif /* UB_UNBOUND_H */

Index: src/external/bsd/unbound/dist/services/authzone.c
diff -u src/external/bsd/unbound/dist/services/authzone.c:1.2 src/external/bsd/unbound/dist/services/authzone.c:1.3
--- src/external/bsd/unbound/dist/services/authzone.c:1.2	Sat Sep 24 14:11:43 2022
+++ src/external/bsd/unbound/dist/services/authzone.c	Sat Feb 17 13:31:18 2024
@@ -1306,8 +1306,8 @@ az_remove_rr(struct auth_zone* z, uint8_
 		auth_data_delete(node);
 	}
 	if(z->rpz) {
-		rpz_remove_rr(z->rpz, z->namelen, dname, dname_len, rr_type,
-			rr_class, rdata, rdatalen);
+		rpz_remove_rr(z->rpz, z->name, z->namelen, dname, dname_len,
+			rr_type, rr_class, rdata, rdatalen);
 	}
 	return 1;
 }
@@ -2475,6 +2475,7 @@ az_find_ce(struct auth_zone* z, struct q
 	struct auth_rrset** rrset)
 {
 	struct auth_data* n = node;
+	struct auth_rrset* lookrrset;
 	*ce = NULL;
 	*rrset = NULL;
 	if(!node_exact) {
@@ -2497,21 +2498,23 @@ az_find_ce(struct auth_zone* z, struct q
 		/* see if the current candidate has issues */
 		/* not zone apex and has type NS */
 		if(n->namelen != z->namelen &&
-			(*rrset=az_domain_rrset(n, LDNS_RR_TYPE_NS)) &&
+			(lookrrset=az_domain_rrset(n, LDNS_RR_TYPE_NS)) &&
 			/* delegate here, but DS at exact the dp has notype */
 			(qinfo->qtype != LDNS_RR_TYPE_DS || 
 			n->namelen != qinfo->qname_len)) {
 			/* referral */
 			/* this is ce and the lowernode is nonexisting */
 			*ce = n;
-			return 0;
+			*rrset = lookrrset;
+			node_exact = 0;
 		}
 		/* not equal to qname and has type DNAME */
 		if(n->namelen != qinfo->qname_len &&
-			(*rrset=az_domain_rrset(n, LDNS_RR_TYPE_DNAME))) {
+			(lookrrset=az_domain_rrset(n, LDNS_RR_TYPE_DNAME))) {
 			/* this is ce and the lowernode is nonexisting */
 			*ce = n;
-			return 0;
+			*rrset = lookrrset;
+			node_exact = 0;
 		}
 
 		if(*ce == NULL && !domain_has_only_nsec3(n)) {
@@ -2756,6 +2759,7 @@ az_change_dnames(struct dns_msg* msg, ui
 			== 0) {
 			msg->rep->rrsets[i]->rk.dname = newname;
 			msg->rep->rrsets[i]->rk.dname_len = newlen;
+			msg->rep->rrsets[i]->entry.hash = rrset_key_hash(&msg->rep->rrsets[i]->rk);
 		}
 	}
 }
@@ -3699,7 +3703,7 @@ addr_matches_master(struct auth_master* 
 	/* compare address (but not port number, that is the destination
 	 * port of the master, the port number of the received notify is
 	 * allowed to by any port on that master) */
-	if(extstrtoaddr(master->host, &a, &alen) &&
+	if(extstrtoaddr(master->host, &a, &alen, UNBOUND_DNS_PORT) &&
 		sockaddr_cmp_addr(addr, addrlen, &a, alen)==0) {
 		*fromhost = master;
 		return 1;
@@ -5381,7 +5385,7 @@ xfr_transfer_lookup_host(struct auth_xfe
 	struct edns_data edns;
 	sldns_buffer* buf = env->scratch_buffer;
 	if(!master) return 0;
-	if(extstrtoaddr(master->host, &addr, &addrlen)) {
+	if(extstrtoaddr(master->host, &addr, &addrlen, UNBOUND_DNS_PORT)) {
 		/* not needed, host is in IP addr format */
 		return 0;
 	}
@@ -5419,6 +5423,8 @@ xfr_transfer_lookup_host(struct auth_xfe
 	edns.opt_list_out = NULL;
 	edns.opt_list_inplace_cb_out = NULL;
 	edns.padding_block_size = 0;
+	edns.cookie_present = 0;
+	edns.cookie_valid = 0;
 	if(sldns_buffer_capacity(buf) < 65535)
 		edns.udp_size = (uint16_t)sldns_buffer_capacity(buf);
 	else	edns.udp_size = 65535;
@@ -6572,7 +6578,7 @@ xfr_probe_lookup_host(struct auth_xfer* 
 	struct edns_data edns;
 	sldns_buffer* buf = env->scratch_buffer;
 	if(!master) return 0;
-	if(extstrtoaddr(master->host, &addr, &addrlen)) {
+	if(extstrtoaddr(master->host, &addr, &addrlen, UNBOUND_DNS_PORT)) {
 		/* not needed, host is in IP addr format */
 		return 0;
 	}
@@ -6612,6 +6618,8 @@ xfr_probe_lookup_host(struct auth_xfer* 
 	edns.opt_list_out = NULL;
 	edns.opt_list_inplace_cb_out = NULL;
 	edns.padding_block_size = 0;
+	edns.cookie_present = 0;
+	edns.cookie_valid = 0;
 	if(sldns_buffer_capacity(buf) < 65535)
 		edns.udp_size = (uint16_t)sldns_buffer_capacity(buf);
 	else	edns.udp_size = 65535;
@@ -7509,7 +7517,7 @@ static void add_rrlist_rrsigs_into_data(
 		size_t j;
 		if(!rrlist[i])
 			continue;
-		if(rrlist[i] && rrlist[i]->type == LDNS_RR_TYPE_ZONEMD &&
+		if(rrlist[i]->type == LDNS_RR_TYPE_ZONEMD &&
 			query_dname_compare(z->name, node->name)==0) {
 			/* omit RRSIGs over type ZONEMD at apex */
 			continue;
@@ -7766,6 +7774,7 @@ static int zonemd_dnssec_verify_rrset(st
 	enum sec_status sec;
 	struct val_env* ve;
 	int m;
+	int verified = 0;
 	m = modstack_find(mods, "validator");
 	if(m == -1) {
 		auth_zone_log(z->name, VERB_ALGO, "zonemd dnssec verify: have "
@@ -7789,7 +7798,7 @@ static int zonemd_dnssec_verify_rrset(st
 			"zonemd: verify %s RRset with DNSKEY", typestr);
 	}
 	sec = dnskeyset_verify_rrset(env, ve, &pk, dnskey, sigalg, why_bogus, NULL,
-		LDNS_SECTION_ANSWER, NULL);
+		LDNS_SECTION_ANSWER, NULL, &verified);
 	if(sec == sec_status_secure) {
 		return 1;
 	}

Index: src/external/bsd/unbound/dist/util/netevent.c
diff -u src/external/bsd/unbound/dist/util/netevent.c:1.5 src/external/bsd/unbound/dist/util/netevent.c:1.6
--- src/external/bsd/unbound/dist/util/netevent.c:1.5	Sat Sep 24 14:11:43 2022
+++ src/external/bsd/unbound/dist/util/netevent.c	Sat Feb 17 13:31:19 2024
@@ -4,22 +4,22 @@
  * Copyright (c) 2007, NLnet Labs. All rights reserved.
  *
  * This software is open source.
- * 
+ *
  * Redistribution and use in source and binary forms, with or without
  * modification, are permitted provided that the following conditions
  * are met:
- * 
+ *
  * Redistributions of source code must retain the above copyright notice,
  * this list of conditions and the following disclaimer.
- * 
+ *
  * Redistributions in binary form must reproduce the above copyright notice,
  * this list of conditions and the following disclaimer in the documentation
  * and/or other materials provided with the distribution.
- * 
+ *
  * Neither the name of the NLNET LABS nor the names of its contributors may
  * be used to endorse or promote products derived from this software without
  * specific prior written permission.
- * 
+ *
  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
  * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
  * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
@@ -45,6 +45,8 @@
 #include "util/net_help.h"
 #include "util/tcp_conn_limit.h"
 #include "util/fptr_wlist.h"
+#include "util/proxy_protocol.h"
+#include "util/timeval_func.h"
 #include "sldns/pkthdr.h"
 #include "sldns/sbuffer.h"
 #include "sldns/str2wire.h"
@@ -60,6 +62,9 @@
 #ifdef HAVE_NETDB_H
 #include <netdb.h>
 #endif
+#ifdef HAVE_POLL_H
+#include <poll.h>
+#endif
 
 #ifdef HAVE_OPENSSL_SSL_H
 #include <openssl/ssl.h>
@@ -67,7 +72,9 @@
 #ifdef HAVE_OPENSSL_ERR_H
 #include <openssl/err.h>
 #endif
-
+#ifdef HAVE_LINUX_NET_TSTAMP_H
+#include <linux/net_tstamp.h>
+#endif
 /* -------- Start of local definitions -------- */
 /** if CMSG_ALIGN is not defined on this platform, a workaround */
 #ifndef CMSG_ALIGN
@@ -107,6 +114,21 @@
 #define NUM_UDP_PER_SELECT 1
 #endif
 
+/** timeout in millisec to wait for write to unblock, packets dropped after.*/
+#define SEND_BLOCKED_WAIT_TIMEOUT 200
+/** max number of times to wait for write to unblock, packets dropped after.*/
+#define SEND_BLOCKED_MAX_RETRY 5
+
+/** Let's make timestamping code cleaner and redefine SO_TIMESTAMP* */
+#ifndef SO_TIMESTAMP
+#define SO_TIMESTAMP 29
+#endif
+#ifndef SO_TIMESTAMPNS
+#define SO_TIMESTAMPNS 35
+#endif
+#ifndef SO_TIMESTAMPING
+#define SO_TIMESTAMPING 37
+#endif
 /**
  * The internal event structure for keeping ub_event info for the event.
  * Possibly other structures (list, tree) this is part of.
@@ -132,6 +154,10 @@ struct internal_base {
 	struct ub_event* slow_accept;
 	/** true if slow_accept is enabled */
 	int slow_accept_enabled;
+	/** last log time for slow logging of file descriptor errors */
+	time_t last_slow_log;
+	/** last log time for slow logging of write wait failures */
+	time_t last_writewait_log;
 };
 
 /**
@@ -166,7 +192,7 @@ static struct comm_point* comm_point_cre
 
 /* -------- End of local definitions -------- */
 
-struct comm_base* 
+struct comm_base*
 comm_base_create(int sigs)
 {
 	struct comm_base* b = (struct comm_base*)calloc(1,
@@ -209,7 +235,7 @@ comm_base_create_event(struct ub_event_b
 	return b;
 }
 
-void 
+void
 comm_base_delete(struct comm_base* b)
 {
 	if(!b)
@@ -226,7 +252,7 @@ comm_base_delete(struct comm_base* b)
 	free(b);
 }
 
-void 
+void
 comm_base_delete_no_base(struct comm_base* b)
 {
 	if(!b)
@@ -242,14 +268,14 @@ comm_base_delete_no_base(struct comm_bas
 	free(b);
 }
 
-void 
+void
 comm_base_timept(struct comm_base* b, time_t** tt, struct timeval** tv)
 {
 	*tt = &b->eb->secs;
 	*tv = &b->eb->now;
 }
 
-void 
+void
 comm_base_dispatch(struct comm_base* b)
 {
 	int retval;
@@ -367,29 +393,131 @@ comm_point_send_udp_msg(struct comm_poin
 		 * we want to send the answer, and we will wait for
 		 * the ethernet interface buffer to have space. */
 #ifndef USE_WINSOCK
-		if(errno == EAGAIN || 
+		if(errno == EAGAIN || errno == EINTR ||
 #  ifdef EWOULDBLOCK
 			errno == EWOULDBLOCK ||
 #  endif
 			errno == ENOBUFS) {
 #else
 		if(WSAGetLastError() == WSAEINPROGRESS ||
+			WSAGetLastError() == WSAEINTR ||
 			WSAGetLastError() == WSAENOBUFS ||
 			WSAGetLastError() == WSAEWOULDBLOCK) {
 #endif
-			int e;
-			fd_set_block(c->fd);
-			if (!is_connected) {
-				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);
+			int retries = 0;
+			/* if we set the fd blocking, other threads suddenly
+			 * have a blocking fd that they operate on */
+			while(sent == -1 && retries < SEND_BLOCKED_MAX_RETRY && (
+#ifndef USE_WINSOCK
+				errno == EAGAIN || errno == EINTR ||
+#  ifdef EWOULDBLOCK
+				errno == EWOULDBLOCK ||
+#  endif
+				errno == ENOBUFS
+#else
+				WSAGetLastError() == WSAEINPROGRESS ||
+				WSAGetLastError() == WSAEINTR ||
+				WSAGetLastError() == WSAENOBUFS ||
+				WSAGetLastError() == WSAEWOULDBLOCK
+#endif
+			)) {
+#if defined(HAVE_POLL) || defined(USE_WINSOCK)
+				int send_nobufs = (
+#ifndef USE_WINSOCK
+					errno == ENOBUFS
+#else
+					WSAGetLastError() == WSAENOBUFS
+#endif
+				);
+				struct pollfd p;
+				int pret;
+				memset(&p, 0, sizeof(p));
+				p.fd = c->fd;
+				p.events = POLLOUT | POLLERR | POLLHUP;
+#  ifndef USE_WINSOCK
+				pret = poll(&p, 1, SEND_BLOCKED_WAIT_TIMEOUT);
+#  else
+				pret = WSAPoll(&p, 1,
+					SEND_BLOCKED_WAIT_TIMEOUT);
+#  endif
+				if(pret == 0) {
+					/* timer expired */
+					struct comm_base* b = c->ev->base;
+					if(b->eb->last_writewait_log+SLOW_LOG_TIME <=
+						b->eb->secs) {
+						b->eb->last_writewait_log = b->eb->secs;
+						verbose(VERB_OPS, "send udp blocked "
+							"for long, dropping packet.");
+					}
+					return 0;
+				} else if(pret < 0 &&
+#ifndef USE_WINSOCK
+					errno != EAGAIN && errno != EINTR &&
+#  ifdef EWOULDBLOCK
+					errno != EWOULDBLOCK &&
+#  endif
+					errno != ENOBUFS
+#else
+					WSAGetLastError() != WSAEINPROGRESS &&
+					WSAGetLastError() != WSAEINTR &&
+					WSAGetLastError() != WSAENOBUFS &&
+					WSAGetLastError() != WSAEWOULDBLOCK
+#endif
+					) {
+					log_err("poll udp out failed: %s",
+						sock_strerror(errno));
+					return 0;
+				} else if((pret < 0 &&
+#ifndef USE_WINSOCK
+					errno == ENOBUFS
+#else
+					WSAGetLastError() == WSAENOBUFS
+#endif
+					) || (send_nobufs && retries > 0)) {
+					/* ENOBUFS, and poll returned without
+					 * a timeout. Or the retried send call
+					 * returned ENOBUFS. It is good to
+					 * wait a bit for the error to clear. */
+					/* The timeout is 20*(2^(retries+1)),
+					 * it increases exponentially, starting
+					 * at 40 msec. After 5 tries, 1240 msec
+					 * have passed in total, when poll
+					 * returned the error, and 1200 msec
+					 * when send returned the errors. */
+#ifndef USE_WINSOCK
+					pret = poll(NULL, 0, (SEND_BLOCKED_WAIT_TIMEOUT/10)<<(retries+1));
+#else
+					pret = WSAPoll(NULL, 0, (SEND_BLOCKED_WAIT_TIMEOUT/10)<<(retries+1));
+#endif
+					if(pret < 0 &&
+#ifndef USE_WINSOCK
+						errno != EAGAIN && errno != EINTR &&
+#  ifdef EWOULDBLOCK
+						errno != EWOULDBLOCK &&
+#  endif
+						errno != ENOBUFS
+#else
+						WSAGetLastError() != WSAEINPROGRESS &&
+						WSAGetLastError() != WSAEINTR &&
+						WSAGetLastError() != WSAENOBUFS &&
+						WSAGetLastError() != WSAEWOULDBLOCK
+#endif
+					) {
+						log_err("poll udp out timer failed: %s",
+							sock_strerror(errno));
+					}
+				}
+#endif /* defined(HAVE_POLL) || defined(USE_WINSOCK) */
+				retries++;
+				if (!is_connected) {
+					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);
+				}
 			}
-			e = errno;
-			fd_set_nonblock(c->fd);
-			errno = e;
 		}
 	}
 	if(sent == -1) {
@@ -405,7 +533,7 @@ comm_point_send_udp_msg(struct comm_poin
 				(struct sockaddr_storage*)addr, addrlen);
 		return 0;
 	} else if((size_t)sent != sldns_buffer_remaining(packet)) {
-		log_err("sent %d in place of %d bytes", 
+		log_err("sent %d in place of %d bytes",
 			(int)sent, (int)sldns_buffer_remaining(packet));
 		return 0;
 	}
@@ -424,7 +552,7 @@ static void p_ancil(const char* str, str
 	if(r->srctype == 6) {
 #ifdef IPV6_PKTINFO
 		char buf[1024];
-		if(inet_ntop(AF_INET6, &r->pktinfo.v6info.ipi6_addr, 
+		if(inet_ntop(AF_INET6, &r->pktinfo.v6info.ipi6_addr,
 			buf, (socklen_t)sizeof(buf)) == 0) {
 			(void)strlcpy(buf, "(inet_ntop error)", sizeof(buf));
 		}
@@ -434,13 +562,13 @@ static void p_ancil(const char* str, str
 	} else if(r->srctype == 4) {
 #ifdef IP_PKTINFO
 		char buf1[1024], buf2[1024];
-		if(inet_ntop(AF_INET, &r->pktinfo.v4info.ipi_addr, 
+		if(inet_ntop(AF_INET, &r->pktinfo.v4info.ipi_addr,
 			buf1, (socklen_t)sizeof(buf1)) == 0) {
 			(void)strlcpy(buf1, "(inet_ntop error)", sizeof(buf1));
 		}
 		buf1[sizeof(buf1)-1]=0;
 #ifdef HAVE_STRUCT_IN_PKTINFO_IPI_SPEC_DST
-		if(inet_ntop(AF_INET, &r->pktinfo.v4info.ipi_spec_dst, 
+		if(inet_ntop(AF_INET, &r->pktinfo.v4info.ipi_spec_dst,
 			buf2, (socklen_t)sizeof(buf2)) == 0) {
 			(void)strlcpy(buf2, "(inet_ntop error)", sizeof(buf2));
 		}
@@ -452,7 +580,7 @@ static void p_ancil(const char* str, str
 			buf1, buf2);
 #elif defined(IP_RECVDSTADDR)
 		char buf1[1024];
-		if(inet_ntop(AF_INET, &r->pktinfo.v4addr, 
+		if(inet_ntop(AF_INET, &r->pktinfo.v4addr,
 			buf1, (socklen_t)sizeof(buf1)) == 0) {
 			(void)strlcpy(buf1, "(inet_ntop error)", sizeof(buf1));
 		}
@@ -466,7 +594,7 @@ static void p_ancil(const char* str, str
 /** send a UDP reply over specified interface*/
 static int
 comm_point_send_udp_msg_if(struct comm_point *c, sldns_buffer* packet,
-	struct sockaddr* addr, socklen_t addrlen, struct comm_reply* r) 
+	struct sockaddr* addr, socklen_t addrlen, struct comm_reply* r)
 {
 #if defined(AF_INET6) && defined(IPV6_PKTINFO) && defined(HAVE_SENDMSG)
 	ssize_t sent;
@@ -514,6 +642,11 @@ comm_point_send_udp_msg_if(struct comm_p
 		cmsg_data = CMSG_DATA(cmsg);
 		((struct in_pktinfo *) cmsg_data)->ipi_ifindex = 0;
 		cmsg->cmsg_len = CMSG_LEN(sizeof(struct in_pktinfo));
+		/* zero the padding bytes inserted by the CMSG_LEN */
+		if(sizeof(struct in_pktinfo) < cmsg->cmsg_len)
+			memset(((uint8_t*)(CMSG_DATA(cmsg))) +
+				sizeof(struct in_pktinfo), 0, cmsg->cmsg_len
+				- sizeof(struct in_pktinfo));
 #elif defined(IP_SENDSRCADDR)
 		msg.msg_controllen = CMSG_SPACE(sizeof(struct in_addr));
 		log_assert(msg.msg_controllen <= sizeof(control.buf));
@@ -522,6 +655,11 @@ comm_point_send_udp_msg_if(struct comm_p
 		memmove(CMSG_DATA(cmsg), &r->pktinfo.v4addr,
 			sizeof(struct in_addr));
 		cmsg->cmsg_len = CMSG_LEN(sizeof(struct in_addr));
+		/* zero the padding bytes inserted by the CMSG_LEN */
+		if(sizeof(struct in_addr) < cmsg->cmsg_len)
+			memset(((uint8_t*)(CMSG_DATA(cmsg))) +
+				sizeof(struct in_addr), 0, cmsg->cmsg_len
+				- sizeof(struct in_addr));
 #else
 		verbose(VERB_ALGO, "no IP_PKTINFO or IP_SENDSRCADDR");
 		msg.msg_control = NULL;
@@ -538,6 +676,11 @@ comm_point_send_udp_msg_if(struct comm_p
 		cmsg_data = CMSG_DATA(cmsg);
 		((struct in6_pktinfo *) cmsg_data)->ipi6_ifindex = 0;
 		cmsg->cmsg_len = CMSG_LEN(sizeof(struct in6_pktinfo));
+		/* zero the padding bytes inserted by the CMSG_LEN */
+		if(sizeof(struct in6_pktinfo) < cmsg->cmsg_len)
+			memset(((uint8_t*)(CMSG_DATA(cmsg))) +
+				sizeof(struct in6_pktinfo), 0, cmsg->cmsg_len
+				- sizeof(struct in6_pktinfo));
 	} else {
 		/* try to pass all 0 to use default route */
 		msg.msg_controllen = CMSG_SPACE(sizeof(struct in6_pktinfo));
@@ -546,9 +689,14 @@ comm_point_send_udp_msg_if(struct comm_p
 		cmsg->cmsg_type = IPV6_PKTINFO;
 		memset(CMSG_DATA(cmsg), 0, sizeof(struct in6_pktinfo));
 		cmsg->cmsg_len = CMSG_LEN(sizeof(struct in6_pktinfo));
+		/* zero the padding bytes inserted by the CMSG_LEN */
+		if(sizeof(struct in6_pktinfo) < cmsg->cmsg_len)
+			memset(((uint8_t*)(CMSG_DATA(cmsg))) +
+				sizeof(struct in6_pktinfo), 0, cmsg->cmsg_len
+				- sizeof(struct in6_pktinfo));
 	}
 #endif /* S_SPLINT_S */
-	if(verbosity >= VERB_ALGO)
+	if(verbosity >= VERB_ALGO && r->srctype != 0)
 		p_ancil("send_udp over interface", r);
 	sent = sendmsg(c->fd, &msg, 0);
 	if(sent == -1) {
@@ -556,29 +704,129 @@ comm_point_send_udp_msg_if(struct comm_p
 		 * we want to send the answer, and we will wait for
 		 * the ethernet interface buffer to have space. */
 #ifndef USE_WINSOCK
-		if(errno == EAGAIN || 
+		if(errno == EAGAIN || errno == EINTR ||
 #  ifdef EWOULDBLOCK
 			errno == EWOULDBLOCK ||
 #  endif
 			errno == ENOBUFS) {
 #else
 		if(WSAGetLastError() == WSAEINPROGRESS ||
+			WSAGetLastError() == WSAEINTR ||
 			WSAGetLastError() == WSAENOBUFS ||
 			WSAGetLastError() == WSAEWOULDBLOCK) {
 #endif
-			int e;
-			fd_set_block(c->fd);
-			sent = sendmsg(c->fd, &msg, 0);
-			e = errno;
-			fd_set_nonblock(c->fd);
-			errno = e;
+			int retries = 0;
+			while(sent == -1 && retries < SEND_BLOCKED_MAX_RETRY && (
+#ifndef USE_WINSOCK
+				errno == EAGAIN || errno == EINTR ||
+#  ifdef EWOULDBLOCK
+				errno == EWOULDBLOCK ||
+#  endif
+				errno == ENOBUFS
+#else
+				WSAGetLastError() == WSAEINPROGRESS ||
+				WSAGetLastError() == WSAEINTR ||
+				WSAGetLastError() == WSAENOBUFS ||
+				WSAGetLastError() == WSAEWOULDBLOCK
+#endif
+			)) {
+#if defined(HAVE_POLL) || defined(USE_WINSOCK)
+				int send_nobufs = (
+#ifndef USE_WINSOCK
+					errno == ENOBUFS
+#else
+					WSAGetLastError() == WSAENOBUFS
+#endif
+				);
+				struct pollfd p;
+				int pret;
+				memset(&p, 0, sizeof(p));
+				p.fd = c->fd;
+				p.events = POLLOUT | POLLERR | POLLHUP;
+#  ifndef USE_WINSOCK
+				pret = poll(&p, 1, SEND_BLOCKED_WAIT_TIMEOUT);
+#  else
+				pret = WSAPoll(&p, 1,
+					SEND_BLOCKED_WAIT_TIMEOUT);
+#  endif
+				if(pret == 0) {
+					/* timer expired */
+					struct comm_base* b = c->ev->base;
+					if(b->eb->last_writewait_log+SLOW_LOG_TIME <=
+						b->eb->secs) {
+						b->eb->last_writewait_log = b->eb->secs;
+						verbose(VERB_OPS, "send udp blocked "
+							"for long, dropping packet.");
+					}
+					return 0;
+				} else if(pret < 0 &&
+#ifndef USE_WINSOCK
+					errno != EAGAIN && errno != EINTR &&
+#  ifdef EWOULDBLOCK
+					errno != EWOULDBLOCK &&
+#  endif
+					errno != ENOBUFS
+#else
+					WSAGetLastError() != WSAEINPROGRESS &&
+					WSAGetLastError() != WSAEINTR &&
+					WSAGetLastError() != WSAENOBUFS &&
+					WSAGetLastError() != WSAEWOULDBLOCK
+#endif
+					) {
+					log_err("poll udp out failed: %s",
+						sock_strerror(errno));
+					return 0;
+				} else if((pret < 0 &&
+#ifndef USE_WINSOCK
+					errno == ENOBUFS
+#else
+					WSAGetLastError() == WSAENOBUFS
+#endif
+					) || (send_nobufs && retries > 0)) {
+					/* ENOBUFS, and poll returned without
+					 * a timeout. Or the retried send call
+					 * returned ENOBUFS. It is good to
+					 * wait a bit for the error to clear. */
+					/* The timeout is 20*(2^(retries+1)),
+					 * it increases exponentially, starting
+					 * at 40 msec. After 5 tries, 1240 msec
+					 * have passed in total, when poll
+					 * returned the error, and 1200 msec
+					 * when send returned the errors. */
+#ifndef USE_WINSOCK
+					pret = poll(NULL, 0, (SEND_BLOCKED_WAIT_TIMEOUT/10)<<(retries+1));
+#else
+					pret = WSAPoll(NULL, 0, (SEND_BLOCKED_WAIT_TIMEOUT/10)<<(retries+1));
+#endif
+					if(pret < 0 &&
+#ifndef USE_WINSOCK
+						errno != EAGAIN && errno != EINTR &&
+#  ifdef EWOULDBLOCK
+						errno != EWOULDBLOCK &&
+#  endif
+						errno != ENOBUFS
+#else
+						WSAGetLastError() != WSAEINPROGRESS &&
+						WSAGetLastError() != WSAEINTR &&
+						WSAGetLastError() != WSAENOBUFS &&
+						WSAGetLastError() != WSAEWOULDBLOCK
+#endif
+					) {
+						log_err("poll udp out timer failed: %s",
+							sock_strerror(errno));
+					}
+				}
+#endif /* defined(HAVE_POLL) || defined(USE_WINSOCK) */
+				retries++;
+				sent = sendmsg(c->fd, &msg, 0);
+			}
 		}
 	}
 	if(sent == -1) {
 		if(!udp_send_errno_needs_log(addr, addrlen))
 			return 0;
 		verbose(VERB_OPS, "sendmsg failed: %s", strerror(errno));
-		log_addr(VERB_OPS, "remote address is", 
+		log_addr(VERB_OPS, "remote address is",
 			(struct sockaddr_storage*)addr, addrlen);
 #ifdef __NetBSD__
 		/* netbsd 7 has IP_PKTINFO for recv but not send */
@@ -588,7 +836,7 @@ comm_point_send_udp_msg_if(struct comm_p
 #endif
 		return 0;
 	} else if((size_t)sent != sldns_buffer_remaining(packet)) {
-		log_err("sent %d in place of %d bytes", 
+		log_err("sent %d in place of %d bytes",
 			(int)sent, (int)sldns_buffer_remaining(packet));
 		return 0;
 	}
@@ -639,10 +887,78 @@ static int udp_recv_needs_log(int err)
 	return 1;
 }
 
-void 
+/** Parses the PROXYv2 header from buf and updates the comm_reply struct.
+ *  Returns 1 on success, 0 on failure. */
+static int consume_pp2_header(struct sldns_buffer* buf, struct comm_reply* rep,
+	int stream) {
+	size_t size;
+	struct pp2_header *header;
+	int err = pp2_read_header(sldns_buffer_begin(buf),
+		sldns_buffer_remaining(buf));
+	if(err) return 0;
+	header = (struct pp2_header*)sldns_buffer_begin(buf);
+	size = PP2_HEADER_SIZE + ntohs(header->len);
+	if((header->ver_cmd & 0xF) == PP2_CMD_LOCAL) {
+		/* A connection from the proxy itself.
+		 * No need to do anything with addresses. */
+		goto done;
+	}
+	if(header->fam_prot == PP2_UNSPEC_UNSPEC) {
+		/* Unspecified family and protocol. This could be used for
+		 * health checks by proxies.
+		 * No need to do anything with addresses. */
+		goto done;
+	}
+	/* Read the proxied address */
+	switch(header->fam_prot) {
+		case PP2_INET_STREAM:
+		case PP2_INET_DGRAM:
+			{
+			struct sockaddr_in* addr =
+				(struct sockaddr_in*)&rep->client_addr;
+			addr->sin_family = AF_INET;
+			addr->sin_addr.s_addr = header->addr.addr4.src_addr;
+			addr->sin_port = header->addr.addr4.src_port;
+			rep->client_addrlen = (socklen_t)sizeof(struct sockaddr_in);
+			}
+			/* Ignore the destination address; it should be us. */
+			break;
+		case PP2_INET6_STREAM:
+		case PP2_INET6_DGRAM:
+			{
+			struct sockaddr_in6* addr =
+				(struct sockaddr_in6*)&rep->client_addr;
+			memset(addr, 0, sizeof(*addr));
+			addr->sin6_family = AF_INET6;
+			memcpy(&addr->sin6_addr,
+				header->addr.addr6.src_addr, 16);
+			addr->sin6_port = header->addr.addr6.src_port;
+			rep->client_addrlen = (socklen_t)sizeof(struct sockaddr_in6);
+			}
+			/* Ignore the destination address; it should be us. */
+			break;
+		default:
+			log_err("proxy_protocol: unsupported family and "
+				"protocol 0x%x", (int)header->fam_prot);
+			return 0;
+	}
+	rep->is_proxied = 1;
+done:
+	if(!stream) {
+		/* We are reading a whole packet;
+		 * Move the rest of the data to overwrite the PROXYv2 header */
+		/* XXX can we do better to avoid memmove? */
+		memmove(header, ((char*)header)+size,
+			sldns_buffer_limit(buf)-size);
+		sldns_buffer_set_limit(buf, sldns_buffer_limit(buf)-size);
+	}
+	return 1;
+}
+
+#if defined(AF_INET6) && defined(IPV6_PKTINFO) && defined(HAVE_RECVMSG)
+void
 comm_point_udp_ancil_callback(int fd, short event, void* arg)
 {
-#if defined(AF_INET6) && defined(IPV6_PKTINFO) && defined(HAVE_RECVMSG)
 	struct comm_reply rep;
 	struct msghdr msg;
 	struct iovec iov[1];
@@ -655,6 +971,9 @@ comm_point_udp_ancil_callback(int fd, sh
 #ifndef S_SPLINT_S
 	struct cmsghdr* cmsg;
 #endif /* S_SPLINT_S */
+#ifdef HAVE_LINUX_NET_TSTAMP_H
+	struct timespec *ts;
+#endif /* HAVE_LINUX_NET_TSTAMP_H */
 
 	rep.c = (struct comm_point*)arg;
 	log_assert(rep.c->type == comm_udp);
@@ -665,11 +984,12 @@ comm_point_udp_ancil_callback(int fd, sh
 	ub_comm_base_now(rep.c->ev->base);
 	for(i=0; i<NUM_UDP_PER_SELECT; i++) {
 		sldns_buffer_clear(rep.c->buffer);
-		rep.addrlen = (socklen_t)sizeof(rep.addr);
+		timeval_clear(&rep.c->recv_tv);
+		rep.remote_addrlen = (socklen_t)sizeof(rep.remote_addr);
 		log_assert(fd != -1);
 		log_assert(sldns_buffer_remaining(rep.c->buffer) > 0);
-		msg.msg_name = &rep.addr;
-		msg.msg_namelen = (socklen_t)sizeof(rep.addr);
+		msg.msg_name = &rep.remote_addr;
+		msg.msg_namelen = (socklen_t)sizeof(rep.remote_addr);
 		iov[0].iov_base = sldns_buffer_begin(rep.c->buffer);
 		iov[0].iov_len = sldns_buffer_remaining(rep.c->buffer);
 		msg.msg_iov = iov;
@@ -679,7 +999,7 @@ comm_point_udp_ancil_callback(int fd, sh
 		msg.msg_controllen = sizeof(ancil.buf);
 #endif /* S_SPLINT_S */
 		msg.msg_flags = 0;
-		rcv = recvmsg(fd, &msg, 0);
+		rcv = recvmsg(fd, &msg, MSG_DONTWAIT);
 		if(rcv == -1) {
 			if(errno != EAGAIN && errno != EINTR
 				&& udp_recv_needs_log(errno)) {
@@ -687,10 +1007,11 @@ comm_point_udp_ancil_callback(int fd, sh
 			}
 			return;
 		}
-		rep.addrlen = msg.msg_namelen;
+		rep.remote_addrlen = msg.msg_namelen;
 		sldns_buffer_skip(rep.c->buffer, rcv);
 		sldns_buffer_flip(rep.c->buffer);
 		rep.srctype = 0;
+		rep.is_proxied = 0;
 #ifndef S_SPLINT_S
 		for(cmsg = CMSG_FIRSTHDR(&msg); cmsg != NULL;
 			cmsg = CMSG_NXTHDR(&msg, cmsg)) {
@@ -715,30 +1036,57 @@ comm_point_udp_ancil_callback(int fd, sh
 					sizeof(struct in_addr));
 				break;
 #endif /* IP_PKTINFO or IP_RECVDSTADDR */
+#ifdef HAVE_LINUX_NET_TSTAMP_H
+			} else if( cmsg->cmsg_level == SOL_SOCKET &&
+				cmsg->cmsg_type == SO_TIMESTAMPNS) {
+				ts = (struct timespec *)CMSG_DATA(cmsg);
+				TIMESPEC_TO_TIMEVAL(&rep.c->recv_tv, ts);
+			} else if( cmsg->cmsg_level == SOL_SOCKET &&
+				cmsg->cmsg_type == SO_TIMESTAMPING) {
+				ts = (struct timespec *)CMSG_DATA(cmsg);
+				TIMESPEC_TO_TIMEVAL(&rep.c->recv_tv, ts);
+			} else if( cmsg->cmsg_level == SOL_SOCKET &&
+				cmsg->cmsg_type == SO_TIMESTAMP) {
+				memmove(&rep.c->recv_tv, CMSG_DATA(cmsg), sizeof(struct timeval));
+#endif /* HAVE_LINUX_NET_TSTAMP_H */
 			}
 		}
-		if(verbosity >= VERB_ALGO)
+
+		if(verbosity >= VERB_ALGO && rep.srctype != 0)
 			p_ancil("receive_udp on interface", &rep);
 #endif /* S_SPLINT_S */
+
+		if(rep.c->pp2_enabled && !consume_pp2_header(rep.c->buffer,
+			&rep, 0)) {
+			log_err("proxy_protocol: could not consume PROXYv2 header");
+			return;
+		}
+		if(!rep.is_proxied) {
+			rep.client_addrlen = rep.remote_addrlen;
+			memmove(&rep.client_addr, &rep.remote_addr,
+				rep.remote_addrlen);
+		}
+
 		fptr_ok(fptr_whitelist_comm_point(rep.c->callback));
 		if((*rep.c->callback)(rep.c, rep.c->cb_arg, NETEVENT_NOERROR, &rep)) {
 			/* send back immediate reply */
-			(void)comm_point_send_udp_msg_if(rep.c, rep.c->buffer,
-				(struct sockaddr*)&rep.addr, rep.addrlen, &rep);
+			struct sldns_buffer *buffer;
+#ifdef USE_DNSCRYPT
+			buffer = rep.c->dnscrypt_buffer;
+#else
+			buffer = rep.c->buffer;
+#endif
+			(void)comm_point_send_udp_msg_if(rep.c, buffer,
+				(struct sockaddr*)&rep.remote_addr,
+				rep.remote_addrlen, &rep);
 		}
 		if(!rep.c || rep.c->fd == -1) /* commpoint closed */
 			break;
 	}
-#else
-	(void)fd;
-	(void)event;
-	(void)arg;
-	fatal_exit("recvmsg: No support for IPV6_PKTINFO; IP_PKTINFO or IP_RECVDSTADDR. "
-		"Please disable interface-automatic");
-#endif /* AF_INET6 && IPV6_PKTINFO && HAVE_RECVMSG */
 }
+#endif /* AF_INET6 && IPV6_PKTINFO && HAVE_RECVMSG */
 
-void 
+void
 comm_point_udp_callback(int fd, short event, void* arg)
 {
 	struct comm_reply rep;
@@ -755,17 +1103,17 @@ comm_point_udp_callback(int fd, short ev
 	ub_comm_base_now(rep.c->ev->base);
 	for(i=0; i<NUM_UDP_PER_SELECT; i++) {
 		sldns_buffer_clear(rep.c->buffer);
-		rep.addrlen = (socklen_t)sizeof(rep.addr);
+		rep.remote_addrlen = (socklen_t)sizeof(rep.remote_addr);
 		log_assert(fd != -1);
 		log_assert(sldns_buffer_remaining(rep.c->buffer) > 0);
-		rcv = recvfrom(fd, (void*)sldns_buffer_begin(rep.c->buffer), 
-			sldns_buffer_remaining(rep.c->buffer), 0, 
-			(struct sockaddr*)&rep.addr, &rep.addrlen);
+		rcv = recvfrom(fd, (void*)sldns_buffer_begin(rep.c->buffer),
+			sldns_buffer_remaining(rep.c->buffer), MSG_DONTWAIT,
+			(struct sockaddr*)&rep.remote_addr, &rep.remote_addrlen);
 		if(rcv == -1) {
 #ifndef USE_WINSOCK
 			if(errno != EAGAIN && errno != EINTR
 				&& udp_recv_needs_log(errno))
-				log_err("recvfrom %d failed: %s", 
+				log_err("recvfrom %d failed: %s",
 					fd, strerror(errno));
 #else
 			if(WSAGetLastError() != WSAEINPROGRESS &&
@@ -780,6 +1128,19 @@ comm_point_udp_callback(int fd, short ev
 		sldns_buffer_skip(rep.c->buffer, rcv);
 		sldns_buffer_flip(rep.c->buffer);
 		rep.srctype = 0;
+		rep.is_proxied = 0;
+
+		if(rep.c->pp2_enabled && !consume_pp2_header(rep.c->buffer,
+			&rep, 0)) {
+			log_err("proxy_protocol: could not consume PROXYv2 header");
+			return;
+		}
+		if(!rep.is_proxied) {
+			rep.client_addrlen = rep.remote_addrlen;
+			memmove(&rep.client_addr, &rep.remote_addr,
+				rep.remote_addrlen);
+		}
+
 		fptr_ok(fptr_whitelist_comm_point(rep.c->callback));
 		if((*rep.c->callback)(rep.c, rep.c->cb_arg, NETEVENT_NOERROR, &rep)) {
 			/* send back immediate reply */
@@ -789,7 +1150,8 @@ comm_point_udp_callback(int fd, short ev
 			buffer = rep.c->buffer;
 #endif
 			(void)comm_point_send_udp_msg(rep.c, buffer,
-				(struct sockaddr*)&rep.addr, rep.addrlen, 0);
+				(struct sockaddr*)&rep.remote_addr,
+				rep.remote_addrlen, 0);
 		}
 		if(!rep.c || rep.c->fd != fd) /* commpoint closed to -1 or reused for
 		another UDP port. Note rep.c cannot be reused with TCP fd. */
@@ -806,7 +1168,7 @@ int adjusted_tcp_timeout(struct comm_poi
 
 /** Use a new tcp handler for new query fd, set to read query */
 static void
-setup_tcp_handler(struct comm_point* c, int fd, int cur, int max) 
+setup_tcp_handler(struct comm_point* c, int fd, int cur, int max)
 {
 	int handler_usage;
 	log_assert(c->type == comm_tcp || c->type == comm_http);
@@ -870,10 +1232,10 @@ int comm_point_perform_accept(struct com
 		/* EINTR is signal interrupt. others are closed connection. */
 		if(	errno == EINTR || errno == EAGAIN
 #ifdef EWOULDBLOCK
-			|| errno == EWOULDBLOCK 
+			|| errno == EWOULDBLOCK
 #endif
 #ifdef ECONNABORTED
-			|| errno == ECONNABORTED 
+			|| errno == ECONNABORTED
 #endif
 #ifdef EPROTO
 			|| errno == EPROTO
@@ -889,6 +1251,16 @@ int comm_point_perform_accept(struct com
 				struct timeval tv;
 				verbose(VERB_ALGO, "out of file descriptors: "
 					"slow accept");
+				ub_comm_base_now(b);
+				if(b->eb->last_slow_log+SLOW_LOG_TIME <=
+					b->eb->secs) {
+					b->eb->last_slow_log = b->eb->secs;
+					verbose(VERB_OPS, "accept failed, "
+						"slow down accept for %d "
+						"msec: %s",
+						NETEVENT_SLOW_ACCEPT_TIME,
+						sock_strerror(errno));
+				}
 				b->eb->slow_accept_enabled = 1;
 				fptr_ok(fptr_whitelist_stop_accept(
 					b->stop_accept));
@@ -909,6 +1281,9 @@ int comm_point_perform_accept(struct com
 					/* we do not want to log here,
 					 * error: "event_add failed." */
 				}
+			} else {
+				log_err("accept, with no slow down, "
+					"failed: %s", sock_strerror(errno));
 			}
 			return -1;
 		}
@@ -1034,7 +1409,7 @@ static int http2_submit_settings(struct 
 #endif /* HAVE_NGHTTP2 */
 
 
-void 
+void
 comm_point_tcp_accept_callback(int fd, short event, void* arg)
 {
 	struct comm_point* c = (struct comm_point*)arg, *c_hdl;
@@ -1092,10 +1467,16 @@ comm_point_tcp_accept_callback(int fd, s
 	}
 	log_assert(fd != -1);
 	(void)fd;
-	new_fd = comm_point_perform_accept(c, &c_hdl->repinfo.addr,
-		&c_hdl->repinfo.addrlen);
+	new_fd = comm_point_perform_accept(c, &c_hdl->repinfo.remote_addr,
+		&c_hdl->repinfo.remote_addrlen);
 	if(new_fd == -1)
 		return;
+	/* Copy remote_address to client_address.
+	 * Simplest way/time for streams to do that. */
+	c_hdl->repinfo.client_addrlen = c_hdl->repinfo.remote_addrlen;
+	memmove(&c_hdl->repinfo.client_addr,
+		&c_hdl->repinfo.remote_addr,
+		c_hdl->repinfo.remote_addrlen);
 	if(c->ssl) {
 		c_hdl->ssl = incoming_ssl_fd(c->ssl, new_fd);
 		if(!c_hdl->ssl) {
@@ -1147,6 +1528,7 @@ reclaim_tcp_handler(struct comm_point* c
 	c->tcp_more_read_again = NULL;
 	c->tcp_more_write_again = NULL;
 	c->tcp_byte_count = 0;
+	c->pp2_header_state = pp2_header_none;
 	sldns_buffer_clear(c->buffer);
 }
 
@@ -1278,8 +1660,8 @@ ssl_handshake(struct comm_point* c)
 				return 0; /* silence reset by peer */
 #endif
 			if(!tcp_connect_errno_needs_log(
-				(struct sockaddr*)&c->repinfo.addr,
-				c->repinfo.addrlen))
+				(struct sockaddr*)&c->repinfo.remote_addr,
+				c->repinfo.remote_addrlen))
 				return 0; /* silence connect failures that
 				show up because after connect this is the
 				first system call that accesses the socket */
@@ -1290,9 +1672,11 @@ ssl_handshake(struct comm_point* c)
 		} else {
 			unsigned long err = ERR_get_error();
 			if(!squelch_err_ssl_handshake(err)) {
-				log_crypto_err_code("ssl handshake failed", err);
-				log_addr(VERB_OPS, "ssl handshake failed", &c->repinfo.addr,
-					c->repinfo.addrlen);
+				log_crypto_err_io_code("ssl handshake failed",
+					want, err);
+				log_addr(VERB_OPS, "ssl handshake failed",
+					&c->repinfo.remote_addr,
+					c->repinfo.remote_addrlen);
 			}
 			return 0;
 		}
@@ -1309,7 +1693,8 @@ ssl_handshake(struct comm_point* c)
 			if(!x) {
 				log_addr(VERB_ALGO, "SSL connection failed: "
 					"no certificate",
-					&c->repinfo.addr, c->repinfo.addrlen);
+					&c->repinfo.remote_addr,
+					c->repinfo.remote_addrlen);
 				return 0;
 			}
 			log_cert(VERB_ALGO, "peer certificate", x);
@@ -1319,13 +1704,13 @@ ssl_handshake(struct comm_point* c)
 				snprintf(buf, sizeof(buf), "SSL connection "
 					"to %s authenticated",
 					SSL_get0_peername(c->ssl));
-				log_addr(VERB_ALGO, buf, &c->repinfo.addr,
-					c->repinfo.addrlen);
+				log_addr(VERB_ALGO, buf, &c->repinfo.remote_addr,
+					c->repinfo.remote_addrlen);
 			} else {
 #endif
 				log_addr(VERB_ALGO, "SSL connection "
-					"authenticated", &c->repinfo.addr,
-					c->repinfo.addrlen);
+					"authenticated", &c->repinfo.remote_addr,
+					c->repinfo.remote_addrlen);
 #ifdef HAVE_SSL_GET0_PEERNAME
 			}
 #endif
@@ -1342,14 +1727,15 @@ ssl_handshake(struct comm_point* c)
 			}
 			log_addr(VERB_ALGO, "SSL connection failed: "
 				"failed to authenticate",
-				&c->repinfo.addr, c->repinfo.addrlen);
+				&c->repinfo.remote_addr,
+				c->repinfo.remote_addrlen);
 			return 0;
 		}
 	} else {
 		/* unauthenticated, the verify peer flag was not set
 		 * in c->ssl when the ssl object was created from ssl_ctx */
-		log_addr(VERB_ALGO, "SSL connection", &c->repinfo.addr,
-			c->repinfo.addrlen);
+		log_addr(VERB_ALGO, "SSL connection", &c->repinfo.remote_addr,
+			c->repinfo.remote_addrlen);
 	}
 
 #ifdef HAVE_SSL_GET0_ALPN_SELECTED
@@ -1390,6 +1776,152 @@ ssl_handle_read(struct comm_point* c)
 		if(c->ssl_shake_state != comm_ssl_shake_none)
 			return 1;
 	}
+	if(c->pp2_enabled && c->pp2_header_state != pp2_header_done) {
+		struct pp2_header* header = NULL;
+		size_t want_read_size = 0;
+		size_t current_read_size = 0;
+		if(c->pp2_header_state == pp2_header_none) {
+			want_read_size = PP2_HEADER_SIZE;
+			if(sldns_buffer_remaining(c->buffer)<want_read_size) {
+				log_err_addr("proxy_protocol: not enough "
+					"buffer size to read PROXYv2 header", "",
+					&c->repinfo.remote_addr,
+					c->repinfo.remote_addrlen);
+				return 0;
+			}
+			verbose(VERB_ALGO, "proxy_protocol: reading fixed "
+				"part of PROXYv2 header (len %lu)",
+				(unsigned long)want_read_size);
+			current_read_size = want_read_size;
+			if(c->tcp_byte_count < current_read_size) {
+				ERR_clear_error();
+				if((r=SSL_read(c->ssl, (void*)sldns_buffer_at(
+					c->buffer, c->tcp_byte_count),
+					current_read_size -
+					c->tcp_byte_count)) <= 0) {
+					int want = SSL_get_error(c->ssl, r);
+					if(want == SSL_ERROR_ZERO_RETURN) {
+						if(c->tcp_req_info)
+							return tcp_req_info_handle_read_close(c->tcp_req_info);
+						return 0; /* shutdown, closed */
+					} else if(want == SSL_ERROR_WANT_READ) {
+#ifdef USE_WINSOCK
+						ub_winsock_tcp_wouldblock(c->ev->ev, UB_EV_READ);
+#endif
+						return 1; /* read more later */
+					} else if(want == SSL_ERROR_WANT_WRITE) {
+						c->ssl_shake_state = comm_ssl_shake_hs_write;
+						comm_point_listen_for_rw(c, 0, 1);
+						return 1;
+					} else if(want == SSL_ERROR_SYSCALL) {
+#ifdef ECONNRESET
+						if(errno == ECONNRESET && verbosity < 2)
+							return 0; /* silence reset by peer */
+#endif
+						if(errno != 0)
+							log_err("SSL_read syscall: %s",
+								strerror(errno));
+						return 0;
+					}
+					log_crypto_err_io("could not SSL_read",
+						want);
+					return 0;
+				}
+				c->tcp_byte_count += r;
+				sldns_buffer_skip(c->buffer, r);
+				if(c->tcp_byte_count != current_read_size) return 1;
+				c->pp2_header_state = pp2_header_init;
+			}
+		}
+		if(c->pp2_header_state == pp2_header_init) {
+			int err;
+			err = pp2_read_header(
+				sldns_buffer_begin(c->buffer),
+				sldns_buffer_limit(c->buffer));
+			if(err) {
+				log_err("proxy_protocol: could not parse "
+					"PROXYv2 header (%s)",
+					pp_lookup_error(err));
+				return 0;
+			}
+			header = (struct pp2_header*)sldns_buffer_begin(c->buffer);
+			want_read_size = ntohs(header->len);
+			if(sldns_buffer_limit(c->buffer) <
+				PP2_HEADER_SIZE + want_read_size) {
+				log_err_addr("proxy_protocol: not enough "
+					"buffer size to read PROXYv2 header", "",
+					&c->repinfo.remote_addr,
+					c->repinfo.remote_addrlen);
+				return 0;
+			}
+			verbose(VERB_ALGO, "proxy_protocol: reading variable "
+				"part of PROXYv2 header (len %lu)",
+				(unsigned long)want_read_size);
+			current_read_size = PP2_HEADER_SIZE + want_read_size;
+			if(want_read_size == 0) {
+				/* nothing more to read; header is complete */
+				c->pp2_header_state = pp2_header_done;
+			} else if(c->tcp_byte_count < current_read_size) {
+				ERR_clear_error();
+				if((r=SSL_read(c->ssl, (void*)sldns_buffer_at(
+					c->buffer, c->tcp_byte_count),
+					current_read_size -
+					c->tcp_byte_count)) <= 0) {
+					int want = SSL_get_error(c->ssl, r);
+					if(want == SSL_ERROR_ZERO_RETURN) {
+						if(c->tcp_req_info)
+							return tcp_req_info_handle_read_close(c->tcp_req_info);
+						return 0; /* shutdown, closed */
+					} else if(want == SSL_ERROR_WANT_READ) {
+#ifdef USE_WINSOCK
+						ub_winsock_tcp_wouldblock(c->ev->ev, UB_EV_READ);
+#endif
+						return 1; /* read more later */
+					} else if(want == SSL_ERROR_WANT_WRITE) {
+						c->ssl_shake_state = comm_ssl_shake_hs_write;
+						comm_point_listen_for_rw(c, 0, 1);
+						return 1;
+					} else if(want == SSL_ERROR_SYSCALL) {
+#ifdef ECONNRESET
+						if(errno == ECONNRESET && verbosity < 2)
+							return 0; /* silence reset by peer */
+#endif
+						if(errno != 0)
+							log_err("SSL_read syscall: %s",
+								strerror(errno));
+						return 0;
+					}
+					log_crypto_err_io("could not SSL_read",
+						want);
+					return 0;
+				}
+				c->tcp_byte_count += r;
+				sldns_buffer_skip(c->buffer, r);
+				if(c->tcp_byte_count != current_read_size) return 1;
+				c->pp2_header_state = pp2_header_done;
+			}
+		}
+		if(c->pp2_header_state != pp2_header_done || !header) {
+			log_err_addr("proxy_protocol: wrong state for the "
+				"PROXYv2 header", "", &c->repinfo.remote_addr,
+				c->repinfo.remote_addrlen);
+			return 0;
+		}
+		sldns_buffer_flip(c->buffer);
+		if(!consume_pp2_header(c->buffer, &c->repinfo, 1)) {
+			log_err_addr("proxy_protocol: could not consume "
+				"PROXYv2 header", "", &c->repinfo.remote_addr,
+				c->repinfo.remote_addrlen);
+			return 0;
+		}
+		verbose(VERB_ALGO, "proxy_protocol: successful read of "
+			"PROXYv2 header");
+		/* Clear and reset the buffer to read the following
+		 * DNS packet(s). */
+		sldns_buffer_clear(c->buffer);
+		c->tcp_byte_count = 0;
+		return 1;
+	}
 	if(c->tcp_byte_count < sizeof(uint16_t)) {
 		/* read length bytes */
 		ERR_clear_error();
@@ -1420,7 +1952,7 @@ ssl_handle_read(struct comm_point* c)
 						strerror(errno));
 				return 0;
 			}
-			log_crypto_err("could not SSL_read");
+			log_crypto_err_io("could not SSL_read", want);
 			return 0;
 		}
 		c->tcp_byte_count += r;
@@ -1470,7 +2002,7 @@ ssl_handle_read(struct comm_point* c)
 						strerror(errno));
 				return 0;
 			}
-			log_crypto_err("could not SSL_read");
+			log_crypto_err_io("could not SSL_read", want);
 			return 0;
 		}
 		sldns_buffer_skip(c->buffer, (ssize_t)r);
@@ -1561,7 +2093,7 @@ ssl_handle_write(struct comm_point* c)
 						strerror(errno));
 				return 0;
 			}
-			log_crypto_err("could not SSL_write");
+			log_crypto_err_io("could not SSL_write", want);
 			return 0;
 		}
 		if(c->tcp_write_and_read) {
@@ -1613,7 +2145,7 @@ ssl_handle_write(struct comm_point* c)
 					strerror(errno));
 			return 0;
 		}
-		log_crypto_err("could not SSL_write");
+		log_crypto_err_io("could not SSL_write", want);
 		return 0;
 	}
 	if(c->tcp_write_and_read) {
@@ -1649,16 +2181,18 @@ ssl_handle_it(struct comm_point* c, int 
 	return ssl_handle_write(c);
 }
 
-/** Handle tcp reading callback. 
+/**
+ * Handle tcp reading callback.
  * @param fd: file descriptor of socket.
  * @param c: comm point to read from into buffer.
  * @param short_ok: if true, very short packets are OK (for comm_local).
- * @return: 0 on error 
+ * @return: 0 on error
  */
 static int
 comm_point_tcp_handle_read(int fd, struct comm_point* c, int short_ok)
 {
 	ssize_t r;
+	int recv_initial = 0;
 	log_assert(c->type == comm_tcp || c->type == comm_local);
 	if(c->ssl)
 		return ssl_handle_it(c, 0);
@@ -1666,78 +2200,119 @@ comm_point_tcp_handle_read(int fd, struc
 		return 0;
 
 	log_assert(fd != -1);
+	if(c->pp2_enabled && c->pp2_header_state != pp2_header_done) {
+		struct pp2_header* header = NULL;
+		size_t want_read_size = 0;
+		size_t current_read_size = 0;
+		if(c->pp2_header_state == pp2_header_none) {
+			want_read_size = PP2_HEADER_SIZE;
+			if(sldns_buffer_remaining(c->buffer)<want_read_size) {
+				log_err_addr("proxy_protocol: not enough "
+					"buffer size to read PROXYv2 header", "",
+					&c->repinfo.remote_addr,
+					c->repinfo.remote_addrlen);
+				return 0;
+			}
+			verbose(VERB_ALGO, "proxy_protocol: reading fixed "
+				"part of PROXYv2 header (len %lu)",
+				(unsigned long)want_read_size);
+			current_read_size = want_read_size;
+			if(c->tcp_byte_count < current_read_size) {
+				r = recv(fd, (void*)sldns_buffer_at(c->buffer,
+					c->tcp_byte_count),
+					current_read_size-c->tcp_byte_count, MSG_DONTWAIT);
+				if(r == 0) {
+					if(c->tcp_req_info)
+						return tcp_req_info_handle_read_close(c->tcp_req_info);
+					return 0;
+				} else if(r == -1) {
+					goto recv_error_initial;
+				}
+				c->tcp_byte_count += r;
+				sldns_buffer_skip(c->buffer, r);
+				if(c->tcp_byte_count != current_read_size) return 1;
+				c->pp2_header_state = pp2_header_init;
+			}
+		}
+		if(c->pp2_header_state == pp2_header_init) {
+			int err;
+			err = pp2_read_header(
+				sldns_buffer_begin(c->buffer),
+				sldns_buffer_limit(c->buffer));
+			if(err) {
+				log_err("proxy_protocol: could not parse "
+					"PROXYv2 header (%s)",
+					pp_lookup_error(err));
+				return 0;
+			}
+			header = (struct pp2_header*)sldns_buffer_begin(c->buffer);
+			want_read_size = ntohs(header->len);
+			if(sldns_buffer_limit(c->buffer) <
+				PP2_HEADER_SIZE + want_read_size) {
+				log_err_addr("proxy_protocol: not enough "
+					"buffer size to read PROXYv2 header", "",
+					&c->repinfo.remote_addr,
+					c->repinfo.remote_addrlen);
+				return 0;
+			}
+			verbose(VERB_ALGO, "proxy_protocol: reading variable "
+				"part of PROXYv2 header (len %lu)",
+				(unsigned long)want_read_size);
+			current_read_size = PP2_HEADER_SIZE + want_read_size;
+			if(want_read_size == 0) {
+				/* nothing more to read; header is complete */
+				c->pp2_header_state = pp2_header_done;
+			} else if(c->tcp_byte_count < current_read_size) {
+				r = recv(fd, (void*)sldns_buffer_at(c->buffer,
+					c->tcp_byte_count),
+					current_read_size-c->tcp_byte_count, MSG_DONTWAIT);
+				if(r == 0) {
+					if(c->tcp_req_info)
+						return tcp_req_info_handle_read_close(c->tcp_req_info);
+					return 0;
+				} else if(r == -1) {
+					goto recv_error;
+				}
+				c->tcp_byte_count += r;
+				sldns_buffer_skip(c->buffer, r);
+				if(c->tcp_byte_count != current_read_size) return 1;
+				c->pp2_header_state = pp2_header_done;
+			}
+		}
+		if(c->pp2_header_state != pp2_header_done || !header) {
+			log_err_addr("proxy_protocol: wrong state for the "
+				"PROXYv2 header", "", &c->repinfo.remote_addr,
+				c->repinfo.remote_addrlen);
+			return 0;
+		}
+		sldns_buffer_flip(c->buffer);
+		if(!consume_pp2_header(c->buffer, &c->repinfo, 1)) {
+			log_err_addr("proxy_protocol: could not consume "
+				"PROXYv2 header", "", &c->repinfo.remote_addr,
+				c->repinfo.remote_addrlen);
+			return 0;
+		}
+		verbose(VERB_ALGO, "proxy_protocol: successful read of "
+			"PROXYv2 header");
+		/* Clear and reset the buffer to read the following
+		    * DNS packet(s). */
+		sldns_buffer_clear(c->buffer);
+		c->tcp_byte_count = 0;
+		return 1;
+	}
+
 	if(c->tcp_byte_count < sizeof(uint16_t)) {
 		/* read length bytes */
 		r = recv(fd,(void*)sldns_buffer_at(c->buffer,c->tcp_byte_count),
-			sizeof(uint16_t)-c->tcp_byte_count, 0);
+			sizeof(uint16_t)-c->tcp_byte_count, MSG_DONTWAIT);
 		if(r == 0) {
 			if(c->tcp_req_info)
 				return tcp_req_info_handle_read_close(c->tcp_req_info);
 			return 0;
 		} else if(r == -1) {
-#ifndef USE_WINSOCK
-			if(errno == EINTR || errno == EAGAIN)
-				return 1;
-#ifdef ECONNRESET
-			if(errno == ECONNRESET && verbosity < 2)
-				return 0; /* silence reset by peer */
-#endif
-#ifdef ECONNREFUSED
-			if(errno == ECONNREFUSED && verbosity < 2)
-				return 0; /* silence reset by peer */
-#endif
-#ifdef ENETUNREACH
-			if(errno == ENETUNREACH && verbosity < 2)
-				return 0; /* silence it */
-#endif
-#ifdef EHOSTDOWN
-			if(errno == EHOSTDOWN && verbosity < 2)
-				return 0; /* silence it */
-#endif
-#ifdef EHOSTUNREACH
-			if(errno == EHOSTUNREACH && verbosity < 2)
-				return 0; /* silence it */
-#endif
-#ifdef ENETDOWN
-			if(errno == ENETDOWN && verbosity < 2)
-				return 0; /* silence it */
-#endif
-#ifdef EACCES
-			if(errno == EACCES && verbosity < 2)
-				return 0; /* silence it */
-#endif
-#ifdef ENOTCONN
-			if(errno == ENOTCONN) {
-				log_err_addr("read (in tcp s) failed and this could be because TCP Fast Open is enabled [--disable-tfo-client --disable-tfo-server] but does not work", sock_strerror(errno),
-					&c->repinfo.addr, c->repinfo.addrlen);
-				return 0;
-			}
-#endif
-#else /* USE_WINSOCK */
-			if(WSAGetLastError() == WSAECONNREFUSED && verbosity < 2)
-				return 0;
-			if(WSAGetLastError() == WSAEHOSTDOWN && verbosity < 2)
-				return 0;
-			if(WSAGetLastError() == WSAEHOSTUNREACH && verbosity < 2)
-				return 0;
-			if(WSAGetLastError() == WSAENETDOWN && verbosity < 2)
-				return 0;
-			if(WSAGetLastError() == WSAENETUNREACH && verbosity < 2)
-				return 0;
-			if(WSAGetLastError() == WSAECONNRESET)
-				return 0;
-			if(WSAGetLastError() == WSAEINPROGRESS)
-				return 1;
-			if(WSAGetLastError() == WSAEWOULDBLOCK) {
-				ub_winsock_tcp_wouldblock(c->ev->ev,
-					UB_EV_READ);
-				return 1;
-			}
-#endif
-			log_err_addr("read (in tcp s)", sock_strerror(errno),
-				&c->repinfo.addr, c->repinfo.addrlen);
-			return 0;
-		} 
+			if(c->pp2_enabled) goto recv_error;
+			goto recv_error_initial;
+		}
 		c->tcp_byte_count += r;
 		if(c->tcp_byte_count != sizeof(uint16_t))
 			return 1;
@@ -1746,52 +2321,114 @@ comm_point_tcp_handle_read(int fd, struc
 			verbose(VERB_QUERY, "tcp: dropped larger than buffer");
 			return 0;
 		}
-		sldns_buffer_set_limit(c->buffer, 
+		sldns_buffer_set_limit(c->buffer,
 			sldns_buffer_read_u16_at(c->buffer, 0));
-		if(!short_ok && 
+		if(!short_ok &&
 			sldns_buffer_limit(c->buffer) < LDNS_HEADER_SIZE) {
 			verbose(VERB_QUERY, "tcp: dropped bogus too short.");
 			return 0;
 		}
-		verbose(VERB_ALGO, "Reading tcp query of length %d", 
+		verbose(VERB_ALGO, "Reading tcp query of length %d",
 			(int)sldns_buffer_limit(c->buffer));
 	}
 
 	if(sldns_buffer_remaining(c->buffer) == 0)
-		log_err("in comm_point_tcp_handle_read buffer_remaining is not > 0 as expected, continuing with (harmless) 0 length recv");
-	r = recv(fd, (void*)sldns_buffer_current(c->buffer), 
-		sldns_buffer_remaining(c->buffer), 0);
+		log_err("in comm_point_tcp_handle_read buffer_remaining is "
+			"not > 0 as expected, continuing with (harmless) 0 "
+			"length recv");
+	r = recv(fd, (void*)sldns_buffer_current(c->buffer),
+		sldns_buffer_remaining(c->buffer), MSG_DONTWAIT);
 	if(r == 0) {
 		if(c->tcp_req_info)
 			return tcp_req_info_handle_read_close(c->tcp_req_info);
 		return 0;
 	} else if(r == -1) {
-#ifndef USE_WINSOCK
-		if(errno == EINTR || errno == EAGAIN)
-			return 1;
-#else /* USE_WINSOCK */
-		if(WSAGetLastError() == WSAECONNRESET)
-			return 0;
-		if(WSAGetLastError() == WSAEINPROGRESS)
-			return 1;
-		if(WSAGetLastError() == WSAEWOULDBLOCK) {
-			ub_winsock_tcp_wouldblock(c->ev->ev, UB_EV_READ);
-			return 1;
-		}
-#endif
-		log_err_addr("read (in tcp r)", sock_strerror(errno),
-			&c->repinfo.addr, c->repinfo.addrlen);
-		return 0;
+		goto recv_error;
 	}
 	sldns_buffer_skip(c->buffer, r);
 	if(sldns_buffer_remaining(c->buffer) <= 0) {
 		tcp_callback_reader(c);
 	}
 	return 1;
+
+recv_error_initial:
+	recv_initial = 1;
+recv_error:
+#ifndef USE_WINSOCK
+	if(errno == EINTR || errno == EAGAIN)
+		return 1;
+	if(recv_initial) {
+#ifdef ECONNRESET
+		if(errno == ECONNRESET && verbosity < 2)
+			return 0; /* silence reset by peer */
+#endif
+#ifdef ECONNREFUSED
+		if(errno == ECONNREFUSED && verbosity < 2)
+			return 0; /* silence reset by peer */
+#endif
+#ifdef ENETUNREACH
+		if(errno == ENETUNREACH && verbosity < 2)
+			return 0; /* silence it */
+#endif
+#ifdef EHOSTDOWN
+		if(errno == EHOSTDOWN && verbosity < 2)
+			return 0; /* silence it */
+#endif
+#ifdef EHOSTUNREACH
+		if(errno == EHOSTUNREACH && verbosity < 2)
+			return 0; /* silence it */
+#endif
+#ifdef ENETDOWN
+		if(errno == ENETDOWN && verbosity < 2)
+			return 0; /* silence it */
+#endif
+#ifdef EACCES
+		if(errno == EACCES && verbosity < 2)
+			return 0; /* silence it */
+#endif
+#ifdef ENOTCONN
+		if(errno == ENOTCONN) {
+			log_err_addr("read (in tcp s) failed and this "
+				"could be because TCP Fast Open is "
+				"enabled [--disable-tfo-client "
+				"--disable-tfo-server] but does not "
+				"work", sock_strerror(errno),
+				&c->repinfo.remote_addr,
+				c->repinfo.remote_addrlen);
+			return 0;
+		}
+#endif
+	}
+#else /* USE_WINSOCK */
+	if(recv_initial) {
+		if(WSAGetLastError() == WSAECONNREFUSED && verbosity < 2)
+			return 0;
+		if(WSAGetLastError() == WSAEHOSTDOWN && verbosity < 2)
+			return 0;
+		if(WSAGetLastError() == WSAEHOSTUNREACH && verbosity < 2)
+			return 0;
+		if(WSAGetLastError() == WSAENETDOWN && verbosity < 2)
+			return 0;
+		if(WSAGetLastError() == WSAENETUNREACH && verbosity < 2)
+			return 0;
+	}
+	if(WSAGetLastError() == WSAECONNRESET)
+		return 0;
+	if(WSAGetLastError() == WSAEINPROGRESS)
+		return 1;
+	if(WSAGetLastError() == WSAEWOULDBLOCK) {
+		ub_winsock_tcp_wouldblock(c->ev->ev,
+			UB_EV_READ);
+		return 1;
+	}
+#endif
+	log_err_addr("read (in tcp s)", sock_strerror(errno),
+		&c->repinfo.remote_addr, c->repinfo.remote_addrlen);
+	return 0;
 }
 
-/** 
- * Handle tcp writing callback. 
+/**
+ * Handle tcp writing callback.
  * @param fd: file descriptor of socket.
  * @param c: comm point to write buffer out of.
  * @return: 0 on error
@@ -1815,7 +2452,7 @@ comm_point_tcp_handle_write(int fd, stru
 		/* from Stevens, unix network programming, vol1, 3rd ed, p450*/
 		int error = 0;
 		socklen_t len = (socklen_t)sizeof(error);
-		if(getsockopt(fd, SOL_SOCKET, SO_ERROR, (void*)&error, 
+		if(getsockopt(fd, SOL_SOCKET, SO_ERROR, (void*)&error,
 			&len) < 0){
 #ifndef USE_WINSOCK
 			error = errno; /* on solaris errno is error */
@@ -1833,7 +2470,8 @@ comm_point_tcp_handle_write(int fd, stru
 			return 0; /* silence lots of chatter in the logs */
                 else if(error != 0) {
 			log_err_addr("tcp connect", strerror(error),
-				&c->repinfo.addr, c->repinfo.addrlen);
+				&c->repinfo.remote_addr,
+				c->repinfo.remote_addrlen);
 #else /* USE_WINSOCK */
 		/* examine error */
 		if(error == WSAEINPROGRESS)
@@ -1845,7 +2483,8 @@ comm_point_tcp_handle_write(int fd, stru
 			return 0;
 		else if(error != 0) {
 			log_err_addr("tcp connect", wsa_strerror(error),
-				&c->repinfo.addr, c->repinfo.addrlen);
+				&c->repinfo.remote_addr,
+				c->repinfo.remote_addrlen);
 #endif /* USE_WINSOCK */
 			return 0;
 		}
@@ -1854,7 +2493,7 @@ comm_point_tcp_handle_write(int fd, stru
 		return ssl_handle_it(c, 1);
 
 #ifdef USE_MSG_FASTOPEN
-	/* Only try this on first use of a connection that uses tfo, 
+	/* Only try this on first use of a connection that uses tfo,
 	   otherwise fall through to normal write */
 	/* Also, TFO support on WINDOWS not implemented at the moment */
 	if(c->tcp_do_fastopen == 1) {
@@ -1877,8 +2516,8 @@ comm_point_tcp_handle_write(int fd, stru
 			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;
+		msg.msg_name = &c->repinfo.remote_addr;
+		msg.msg_namelen = c->repinfo.remote_addrlen;
 		msg.msg_iov = iov;
 		msg.msg_iovlen = 2;
 		r = sendmsg(fd, &msg, MSG_FASTOPEN);
@@ -1904,14 +2543,16 @@ comm_point_tcp_handle_write(int fd, stru
 				if(verbosity < 2)
 					return 0; /* silence lots of chatter in the logs */
 				log_err_addr("tcp sendmsg", strerror(errno),
-					&c->repinfo.addr, c->repinfo.addrlen);
+					&c->repinfo.remote_addr,
+					c->repinfo.remote_addrlen);
 				return 0;
 			}
 			verbose(VERB_ALGO, "tcp sendmsg for fastopen failed (with %s), try normal connect", strerror(errno));
 			/* fallthrough to nonFASTOPEN
 			 * (MSG_FASTOPEN on Linux 3 produces EPIPE)
 			 * we need to perform connect() */
-			if(connect(fd, (struct sockaddr *)&c->repinfo.addr, c->repinfo.addrlen) == -1) {
+			if(connect(fd, (struct sockaddr *)&c->repinfo.remote_addr,
+				c->repinfo.remote_addrlen) == -1) {
 #ifdef EINPROGRESS
 				if(errno == EINPROGRESS)
 					return 1; /* wait until connect done*/
@@ -1922,9 +2563,12 @@ comm_point_tcp_handle_write(int fd, stru
 					return 1; /* wait until connect done*/
 #endif
 				if(tcp_connect_errno_needs_log(
-					(struct sockaddr *)&c->repinfo.addr, c->repinfo.addrlen)) {
+					(struct sockaddr *)&c->repinfo.remote_addr,
+					c->repinfo.remote_addrlen)) {
 					log_err_addr("outgoing tcp: connect after EPIPE for fastopen",
-						strerror(errno), &c->repinfo.addr, c->repinfo.addrlen);
+						strerror(errno),
+						&c->repinfo.remote_addr,
+						c->repinfo.remote_addrlen);
 				}
 				return 0;
 			}
@@ -1989,10 +2633,12 @@ comm_point_tcp_handle_write(int fd, stru
 #endif
 #  ifdef HAVE_WRITEV
 			log_err_addr("tcp writev", strerror(errno),
-				&c->repinfo.addr, c->repinfo.addrlen);
+				&c->repinfo.remote_addr,
+				c->repinfo.remote_addrlen);
 #  else /* HAVE_WRITEV */
 			log_err_addr("tcp send s", strerror(errno),
-				&c->repinfo.addr, c->repinfo.addrlen);
+				&c->repinfo.remote_addr,
+				c->repinfo.remote_addrlen);
 #  endif /* HAVE_WRITEV */
 #else
 			if(WSAGetLastError() == WSAENOTCONN)
@@ -2002,13 +2648,14 @@ comm_point_tcp_handle_write(int fd, stru
 			if(WSAGetLastError() == WSAEWOULDBLOCK) {
 				ub_winsock_tcp_wouldblock(c->ev->ev,
 					UB_EV_WRITE);
-				return 1; 
+				return 1;
 			}
 			if(WSAGetLastError() == WSAECONNRESET && verbosity < 2)
 				return 0; /* silence reset by peer */
 			log_err_addr("tcp send s",
 				wsa_strerror(WSAGetLastError()),
-				&c->repinfo.addr, c->repinfo.addrlen);
+				&c->repinfo.remote_addr,
+				c->repinfo.remote_addrlen);
 #endif
 			return 0;
 		}
@@ -2050,13 +2697,14 @@ comm_point_tcp_handle_write(int fd, stru
 			return 1;
 		if(WSAGetLastError() == WSAEWOULDBLOCK) {
 			ub_winsock_tcp_wouldblock(c->ev->ev, UB_EV_WRITE);
-			return 1; 
+			return 1;
 		}
 		if(WSAGetLastError() == WSAECONNRESET && verbosity < 2)
 			return 0; /* silence reset by peer */
 #endif
 		log_err_addr("tcp send r", sock_strerror(errno),
-			&c->repinfo.addr, c->repinfo.addrlen);
+			&c->repinfo.remote_addr,
+			c->repinfo.remote_addrlen);
 		return 0;
 	}
 	if(c->tcp_write_and_read) {
@@ -2068,12 +2716,13 @@ comm_point_tcp_handle_write(int fd, stru
 	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;
 }
 
-/** read again to drain buffers when there could be more to read */
-static void
+/** read again to drain buffers when there could be more to read, returns 0
+ * on failure which means the comm point is closed. */
+static int
 tcp_req_info_read_again(int fd, struct comm_point* c)
 {
 	while(c->tcp_req_info->read_again) {
@@ -2087,12 +2736,13 @@ tcp_req_info_read_again(int fd, struct 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;
+			return 0;
 		}
 	}
+	return 1;
 }
 
 /** read again to drain buffers when there could be more to read */
@@ -2143,13 +2793,16 @@ tcp_more_write_again(int fd, struct comm
 	}
 }
 
-void 
+void
 comm_point_tcp_handle_callback(int fd, short event, void* arg)
 {
 	struct comm_point* c = (struct comm_point*)arg;
 	log_assert(c->type == comm_tcp);
 	ub_comm_base_now(c->ev->base);
 
+	if(c->fd == -1 || c->fd != fd)
+		return; /* duplicate event, but commpoint closed. */
+
 #ifdef USE_DNSCRYPT
 	/* Initialize if this is a dnscrypt socket */
 	if(c->tcp_parent) {
@@ -2198,8 +2851,10 @@ comm_point_tcp_handle_callback(int fd, s
 			}
 			return;
 		}
-		if(has_tcpq && c->tcp_req_info && c->tcp_req_info->read_again)
-			tcp_req_info_read_again(fd, c);
+		if(has_tcpq && c->tcp_req_info && c->tcp_req_info->read_again) {
+			if(!tcp_req_info_read_again(fd, c))
+				return;
+		}
 		if(moreread && *moreread)
 			tcp_more_read_again(fd, c);
 		return;
@@ -2217,8 +2872,10 @@ comm_point_tcp_handle_callback(int fd, s
 			}
 			return;
 		}
-		if(has_tcpq && c->tcp_req_info && c->tcp_req_info->read_again)
-			tcp_req_info_read_again(fd, c);
+		if(has_tcpq && c->tcp_req_info && c->tcp_req_info->read_again) {
+			if(!tcp_req_info_read_again(fd, c))
+				return;
+		}
 		if(morewrite && *morewrite)
 			tcp_more_write_again(fd, c);
 		return;
@@ -2282,7 +2939,7 @@ ssl_http_read_more(struct comm_point* c)
 					strerror(errno));
 			return 0;
 		}
-		log_crypto_err("could not SSL_read");
+		log_crypto_err_io("could not SSL_read", want);
 		return 0;
 	}
 	verbose(VERB_ALGO, "ssl http read more skip to %d + %d",
@@ -2301,8 +2958,8 @@ http_read_more(int fd, struct comm_point
 {
 	ssize_t r;
 	log_assert(sldns_buffer_remaining(c->buffer) > 0);
-	r = recv(fd, (void*)sldns_buffer_current(c->buffer), 
-		sldns_buffer_remaining(c->buffer), 0);
+	r = recv(fd, (void*)sldns_buffer_current(c->buffer),
+		sldns_buffer_remaining(c->buffer), MSG_DONTWAIT);
 	if(r == 0) {
 		return 0;
 	} else if(r == -1) {
@@ -2320,7 +2977,7 @@ http_read_more(int fd, struct comm_point
 		}
 #endif
 		log_err_addr("read (in http r)", sock_strerror(errno),
-			&c->repinfo.addr, c->repinfo.addrlen);
+			&c->repinfo.remote_addr, c->repinfo.remote_addrlen);
 		return 0;
 	}
 	verbose(VERB_ALGO, "http read more skip to %d + %d",
@@ -2570,7 +3227,7 @@ http_chunked_segment(struct comm_point* 
 		/* return and wait to read more */
 		return 1;
 	}
-	
+
 	/* callback of http reader for a new part of the data */
 	c->http_stored = 0;
 	sldns_buffer_set_position(c->buffer, 0);
@@ -2733,14 +3390,14 @@ ssize_t http2_recv_cb(nghttp2_session* A
 						strerror(errno));
 				return NGHTTP2_ERR_CALLBACK_FAILURE;
 			}
-			log_crypto_err("could not SSL_read");
+			log_crypto_err_io("could not SSL_read", want);
 			return NGHTTP2_ERR_CALLBACK_FAILURE;
 		}
 		return r;
 	}
 #endif /* HAVE_SSL */
 
-	ret = recv(h2_session->c->fd, buf, len, 0);
+	ret = recv(h2_session->c->fd, buf, len, MSG_DONTWAIT);
 	if(ret == 0) {
 		return NGHTTP2_ERR_EOF;
 	} else if(ret < 0) {
@@ -2752,8 +3409,8 @@ ssize_t http2_recv_cb(nghttp2_session* A
 			return NGHTTP2_ERR_CALLBACK_FAILURE;
 #endif
 		log_err_addr("could not http2 recv: %s", strerror(errno),
-			&h2_session->c->repinfo.addr,
-			h2_session->c->repinfo.addrlen);
+			&h2_session->c->repinfo.remote_addr,
+			h2_session->c->repinfo.remote_addrlen);
 #else /* USE_WINSOCK */
 		if(WSAGetLastError() == WSAECONNRESET)
 			return NGHTTP2_ERR_CALLBACK_FAILURE;
@@ -2766,8 +3423,8 @@ ssize_t http2_recv_cb(nghttp2_session* A
 		}
 		log_err_addr("could not http2 recv: %s",
 			wsa_strerror(WSAGetLastError()),
-			&h2_session->c->repinfo.addr,
-			h2_session->c->repinfo.addrlen);
+			&h2_session->c->repinfo.remote_addr,
+			h2_session->c->repinfo.remote_addrlen);
 #endif
 		return NGHTTP2_ERR_CALLBACK_FAILURE;
 	}
@@ -2789,8 +3446,8 @@ comm_point_http2_handle_read(int ATTR_UN
 		if(ret != NGHTTP2_ERR_EOF &&
 			ret != NGHTTP2_ERR_CALLBACK_FAILURE) {
 			char a[256];
-			addr_to_str(&c->repinfo.addr, c->repinfo.addrlen,
-				a, sizeof(a));
+			addr_to_str(&c->repinfo.remote_addr,
+				c->repinfo.remote_addrlen, a, sizeof(a));
 			verbose(VERB_QUERY, "http2: session_recv from %s failed, "
 				"error: %s", a, nghttp2_strerror(ret));
 		}
@@ -2920,7 +3577,7 @@ http_check_connect(int fd, struct comm_p
 	/* from Stevens, unix network programming, vol1, 3rd ed, p450*/
 	int error = 0;
 	socklen_t len = (socklen_t)sizeof(error);
-	if(getsockopt(fd, SOL_SOCKET, SO_ERROR, (void*)&error, 
+	if(getsockopt(fd, SOL_SOCKET, SO_ERROR, (void*)&error,
 		&len) < 0){
 #ifndef USE_WINSOCK
 		error = errno; /* on solaris errno is error */
@@ -2938,7 +3595,7 @@ http_check_connect(int fd, struct comm_p
 		return 0; /* silence lots of chatter in the logs */
 	else if(error != 0) {
 		log_err_addr("http connect", strerror(error),
-			&c->repinfo.addr, c->repinfo.addrlen);
+			&c->repinfo.remote_addr, c->repinfo.remote_addrlen);
 #else /* USE_WINSOCK */
 	/* examine error */
 	if(error == WSAEINPROGRESS)
@@ -2950,7 +3607,7 @@ http_check_connect(int fd, struct comm_p
 		return 0;
 	else if(error != 0) {
 		log_err_addr("http connect", wsa_strerror(error),
-			&c->repinfo.addr, c->repinfo.addrlen);
+			&c->repinfo.remote_addr, c->repinfo.remote_addrlen);
 #endif /* USE_WINSOCK */
 		return 0;
 	}
@@ -2988,7 +3645,7 @@ ssl_http_write_more(struct comm_point* c
 					strerror(errno));
 			return 0;
 		}
-		log_crypto_err("could not SSL_write");
+		log_crypto_err_io("could not SSL_write", want);
 		return 0;
 	}
 	sldns_buffer_skip(c->buffer, (ssize_t)r);
@@ -3005,7 +3662,7 @@ http_write_more(int fd, struct comm_poin
 {
 	ssize_t r;
 	log_assert(sldns_buffer_remaining(c->buffer) > 0);
-	r = send(fd, (void*)sldns_buffer_current(c->buffer), 
+	r = send(fd, (void*)sldns_buffer_current(c->buffer),
 		sldns_buffer_remaining(c->buffer), 0);
 	if(r == -1) {
 #ifndef USE_WINSOCK
@@ -3016,11 +3673,11 @@ http_write_more(int fd, struct comm_poin
 			return 1;
 		if(WSAGetLastError() == WSAEWOULDBLOCK) {
 			ub_winsock_tcp_wouldblock(c->ev->ev, UB_EV_WRITE);
-			return 1; 
+			return 1;
 		}
 #endif
 		log_err_addr("http send r", sock_strerror(errno),
-			&c->repinfo.addr, c->repinfo.addrlen);
+			&c->repinfo.remote_addr, c->repinfo.remote_addrlen);
 		return 0;
 	}
 	sldns_buffer_skip(c->buffer, r);
@@ -3061,7 +3718,7 @@ ssize_t http2_send_cb(nghttp2_session* A
 						strerror(errno));
 				return NGHTTP2_ERR_CALLBACK_FAILURE;
 			}
-			log_crypto_err("could not SSL_write");
+			log_crypto_err_io("could not SSL_write", want);
 			return NGHTTP2_ERR_CALLBACK_FAILURE;
 		}
 		return r;
@@ -3084,8 +3741,8 @@ ssize_t http2_send_cb(nghttp2_session* A
 			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);
+			&h2_session->c->repinfo.remote_addr,
+			h2_session->c->repinfo.remote_addrlen);
 #else /* USE_WINSOCK */
 		if(WSAGetLastError() == WSAENOTCONN)
 			return NGHTTP2_ERR_WOULDBLOCK;
@@ -3100,8 +3757,8 @@ ssize_t http2_send_cb(nghttp2_session* A
 			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);
+			&h2_session->c->repinfo.remote_addr,
+			h2_session->c->repinfo.remote_addrlen);
 #endif
 		return NGHTTP2_ERR_CALLBACK_FAILURE;
 	}
@@ -3137,8 +3794,8 @@ comm_point_http2_handle_write(int ATTR_U
 #endif
 }
 
-/** 
- * Handle http writing callback. 
+/**
+ * Handle http writing callback.
  * @param fd: file descriptor of socket.
  * @param c: comm point to write buffer out of.
  * @return: 0 on error
@@ -3204,7 +3861,7 @@ comm_point_http_handle_write(int fd, str
 	return 1;
 }
 
-void 
+void
 comm_point_http_handle_callback(int fd, short event, void* arg)
 {
 	struct comm_point* c = (struct comm_point*)arg;
@@ -3257,7 +3914,7 @@ void comm_point_local_handle_callback(in
 	if(event&UB_EV_READ) {
 		if(!comm_point_tcp_handle_read(fd, c, 1)) {
 			fptr_ok(fptr_whitelist_comm_point(c->callback));
-			(void)(*c->callback)(c, c->cb_arg, NETEVENT_CLOSED, 
+			(void)(*c->callback)(c, c->cb_arg, NETEVENT_CLOSED,
 				NULL);
 		}
 		return;
@@ -3265,23 +3922,24 @@ void comm_point_local_handle_callback(in
 	log_err("Ignored event %d for localhdl.", event);
 }
 
-void comm_point_raw_handle_callback(int ATTR_UNUSED(fd), 
+void comm_point_raw_handle_callback(int ATTR_UNUSED(fd),
 	short event, void* arg)
 {
 	struct comm_point* c = (struct comm_point*)arg;
 	int err = NETEVENT_NOERROR;
 	log_assert(c->type == comm_raw);
 	ub_comm_base_now(c->ev->base);
-	
+
 	if(event&UB_EV_TIMEOUT)
 		err = NETEVENT_TIMEOUT;
 	fptr_ok(fptr_whitelist_comm_point_raw(c->callback));
 	(void)(*c->callback)(c, c->cb_arg, err, NULL);
 }
 
-struct comm_point* 
+struct comm_point*
 comm_point_create_udp(struct comm_base *base, int fd, sldns_buffer* buffer,
-	comm_point_callback_type* callback, void* callback_arg, struct unbound_socket* socket)
+	int pp2_enabled, comm_point_callback_type* callback,
+	void* callback_arg, struct unbound_socket* socket)
 {
 	struct comm_point* c = (struct comm_point*)calloc(1,
 		sizeof(struct comm_point));
@@ -3321,6 +3979,8 @@ comm_point_create_udp(struct comm_base *
 	c->callback = callback;
 	c->cb_arg = callback_arg;
 	c->socket = socket;
+	c->pp2_enabled = pp2_enabled;
+	c->pp2_header_state = pp2_header_none;
 	evbits = UB_EV_READ | UB_EV_PERSIST;
 	/* ub_event stuff */
 	c->ev->ev = ub_event_new(base->eb->base, c->fd, evbits,
@@ -3339,9 +3999,10 @@ comm_point_create_udp(struct comm_base *
 	return c;
 }
 
-struct comm_point* 
-comm_point_create_udp_ancil(struct comm_base *base, int fd, 
-	sldns_buffer* buffer, 
+#if defined(AF_INET6) && defined(IPV6_PKTINFO) && defined(HAVE_RECVMSG)
+struct comm_point*
+comm_point_create_udp_ancil(struct comm_base *base, int fd,
+	sldns_buffer* buffer, int pp2_enabled,
 	comm_point_callback_type* callback, void* callback_arg, struct unbound_socket* socket)
 {
 	struct comm_point* c = (struct comm_point*)calloc(1,
@@ -3382,6 +4043,8 @@ comm_point_create_udp_ancil(struct comm_
 	c->callback = callback;
 	c->cb_arg = callback_arg;
 	c->socket = socket;
+	c->pp2_enabled = pp2_enabled;
+	c->pp2_header_state = pp2_header_none;
 	evbits = UB_EV_READ | UB_EV_PERSIST;
 	/* ub_event stuff */
 	c->ev->ev = ub_event_new(base->eb->base, c->fd, evbits,
@@ -3399,9 +4062,10 @@ comm_point_create_udp_ancil(struct comm_
 	c->event_added = 1;
 	return c;
 }
+#endif
 
-static struct comm_point* 
-comm_point_create_tcp_handler(struct comm_base *base, 
+static struct comm_point*
+comm_point_create_tcp_handler(struct comm_base *base,
 	struct comm_point* parent, size_t bufsize,
 	struct sldns_buffer* spoolbuf, comm_point_callback_type* callback,
 	void* callback_arg, struct unbound_socket* socket)
@@ -3461,6 +4125,8 @@ comm_point_create_tcp_handler(struct com
 	c->callback = callback;
 	c->cb_arg = callback_arg;
 	c->socket = socket;
+	c->pp2_enabled = parent->pp2_enabled;
+	c->pp2_header_state = pp2_header_none;
 	if(spoolbuf) {
 		c->tcp_req_info = tcp_req_info_create(spoolbuf);
 		if(!c->tcp_req_info) {
@@ -3496,8 +4162,8 @@ comm_point_create_tcp_handler(struct com
 	return c;
 }
 
-static struct comm_point* 
-comm_point_create_http_handler(struct comm_base *base, 
+static struct comm_point*
+comm_point_create_http_handler(struct comm_base *base,
 	struct comm_point* parent, size_t bufsize, int harden_large_queries,
 	uint32_t http_max_streams, char* http_endpoint,
 	comm_point_callback_type* callback, void* callback_arg,
@@ -3556,6 +4222,8 @@ comm_point_create_http_handler(struct co
 	c->callback = callback;
 	c->cb_arg = callback_arg;
 	c->socket = socket;
+	c->pp2_enabled = 0;
+	c->pp2_header_state = pp2_header_none;
 
 	c->http_min_version = http_version_2;
 	c->http2_stream_max_qbuffer_size = bufsize;
@@ -3592,7 +4260,7 @@ comm_point_create_http_handler(struct co
 		return NULL;
 	}
 #endif
-	
+
 	/* add to parent free list */
 	c->tcp_free = parent->tcp_free;
 	parent->tcp_free = c;
@@ -3614,13 +4282,14 @@ comm_point_create_http_handler(struct co
 	return c;
 }
 
-struct comm_point* 
+struct comm_point*
 comm_point_create_tcp(struct comm_base *base, int fd, int num,
 	int idle_timeout, int harden_large_queries,
 	uint32_t http_max_streams, char* http_endpoint,
 	struct tcl_list* tcp_conn_limit, size_t bufsize,
 	struct sldns_buffer* spoolbuf, enum listen_type port_type,
-	comm_point_callback_type* callback, void* callback_arg, struct unbound_socket* socket)
+	int pp2_enabled, comm_point_callback_type* callback,
+	void* callback_arg, struct unbound_socket* socket)
 {
 	struct comm_point* c = (struct comm_point*)calloc(1,
 		sizeof(struct comm_point));
@@ -3671,6 +4340,8 @@ comm_point_create_tcp(struct comm_base *
 	c->callback = NULL;
 	c->cb_arg = NULL;
 	c->socket = socket;
+	c->pp2_enabled = (port_type==listen_type_http?0:pp2_enabled);
+	c->pp2_header_state = pp2_header_none;
 	evbits = UB_EV_READ | UB_EV_PERSIST;
 	/* ub_event stuff */
 	c->ev->ev = ub_event_new(base->eb->base, c->fd, evbits,
@@ -3709,11 +4380,11 @@ comm_point_create_tcp(struct comm_base *
 			return NULL;
 		}
 	}
-	
+
 	return c;
 }
 
-struct comm_point* 
+struct comm_point*
 comm_point_create_tcp_out(struct comm_base *base, size_t bufsize,
         comm_point_callback_type* callback, void* callback_arg)
 {
@@ -3763,6 +4434,8 @@ comm_point_create_tcp_out(struct comm_ba
 	c->repinfo.c = c;
 	c->callback = callback;
 	c->cb_arg = callback_arg;
+	c->pp2_enabled = 0;
+	c->pp2_header_state = pp2_header_none;
 	evbits = UB_EV_PERSIST | UB_EV_WRITE;
 	c->ev->ev = ub_event_new(base->eb->base, c->fd, evbits,
 		comm_point_tcp_handle_callback, c);
@@ -3778,7 +4451,7 @@ comm_point_create_tcp_out(struct comm_ba
 	return c;
 }
 
-struct comm_point* 
+struct comm_point*
 comm_point_create_http_out(struct comm_base *base, size_t bufsize,
         comm_point_callback_type* callback, void* callback_arg,
 	sldns_buffer* temp)
@@ -3829,6 +4502,8 @@ comm_point_create_http_out(struct comm_b
 	c->repinfo.c = c;
 	c->callback = callback;
 	c->cb_arg = callback_arg;
+	c->pp2_enabled = 0;
+	c->pp2_header_state = pp2_header_none;
 	evbits = UB_EV_PERSIST | UB_EV_WRITE;
 	c->ev->ev = ub_event_new(base->eb->base, c->fd, evbits,
 		comm_point_http_handle_callback, c);
@@ -3847,7 +4522,7 @@ comm_point_create_http_out(struct comm_b
 	return c;
 }
 
-struct comm_point* 
+struct comm_point*
 comm_point_create_local(struct comm_base *base, int fd, size_t bufsize,
         comm_point_callback_type* callback, void* callback_arg)
 {
@@ -3892,6 +4567,8 @@ comm_point_create_local(struct comm_base
 #endif
 	c->callback = callback;
 	c->cb_arg = callback_arg;
+	c->pp2_enabled = 0;
+	c->pp2_header_state = pp2_header_none;
 	/* ub_event stuff */
 	evbits = UB_EV_PERSIST | UB_EV_READ;
 	c->ev->ev = ub_event_new(base->eb->base, c->fd, evbits,
@@ -3913,8 +4590,8 @@ comm_point_create_local(struct comm_base
 	return c;
 }
 
-struct comm_point* 
-comm_point_create_raw(struct comm_base* base, int fd, int writing, 
+struct comm_point*
+comm_point_create_raw(struct comm_base* base, int fd, int writing,
 	comm_point_callback_type* callback, void* callback_arg)
 {
 	struct comm_point* c = (struct comm_point*)calloc(1,
@@ -3953,6 +4630,8 @@ comm_point_create_raw(struct comm_base* 
 #endif
 	c->callback = callback;
 	c->cb_arg = callback_arg;
+	c->pp2_enabled = 0;
+	c->pp2_header_state = pp2_header_none;
 	/* ub_event stuff */
 	if(writing)
 		evbits = UB_EV_PERSIST | UB_EV_WRITE;
@@ -3976,7 +4655,7 @@ comm_point_create_raw(struct comm_base* 
 	return c;
 }
 
-void 
+void
 comm_point_close(struct comm_point* c)
 {
 	if(!c)
@@ -3995,6 +4674,11 @@ comm_point_close(struct comm_point* c)
 		tcp_req_info_clear(c->tcp_req_info);
 	if(c->h2_session)
 		http2_session_server_delete(c->h2_session);
+	/* stop the comm point from reading or writing after it is closed. */
+	if(c->tcp_more_read_again && *c->tcp_more_read_again)
+		*c->tcp_more_read_again = 0;
+	if(c->tcp_more_write_again && *c->tcp_more_write_again)
+		*c->tcp_more_write_again = 0;
 
 	/* close fd after removing from event lists, or epoll.. is messed up */
 	if(c->fd != -1 && !c->do_not_close) {
@@ -4011,10 +4695,10 @@ comm_point_close(struct comm_point* c)
 	c->fd = -1;
 }
 
-void 
+void
 comm_point_delete(struct comm_point* c)
 {
-	if(!c) 
+	if(!c)
 		return;
 	if((c->type == comm_tcp || c->type == comm_http) && c->ssl) {
 #ifdef HAVE_SSL
@@ -4053,7 +4737,7 @@ comm_point_delete(struct comm_point* c)
 	free(c);
 }
 
-void 
+void
 comm_point_send_reply(struct comm_reply *repinfo)
 {
 	struct sldns_buffer* buffer;
@@ -4068,20 +4752,21 @@ comm_point_send_reply(struct comm_reply 
 #endif
 	if(repinfo->c->type == comm_udp) {
 		if(repinfo->srctype)
-			comm_point_send_udp_msg_if(repinfo->c, 
-			buffer, (struct sockaddr*)&repinfo->addr, 
-			repinfo->addrlen, repinfo);
+			comm_point_send_udp_msg_if(repinfo->c, buffer,
+				(struct sockaddr*)&repinfo->remote_addr,
+				repinfo->remote_addrlen, repinfo);
 		else
 			comm_point_send_udp_msg(repinfo->c, buffer,
-			(struct sockaddr*)&repinfo->addr, repinfo->addrlen, 0);
+				(struct sockaddr*)&repinfo->remote_addr,
+				repinfo->remote_addrlen, 0);
 #ifdef USE_DNSTAP
 		/*
 		 * sending src (client)/dst (local service) addresses over DNSTAP from udp callback
 		 */
 		if(repinfo->c->dtenv != NULL && repinfo->c->dtenv->log_client_response_messages) {
 			log_addr(VERB_ALGO, "from local addr", (void*)repinfo->c->socket->addr->ai_addr, repinfo->c->socket->addr->ai_addrlen);
-			log_addr(VERB_ALGO, "response to client", &repinfo->addr, repinfo->addrlen);
-			dt_msg_send_client_response(repinfo->c->dtenv, &repinfo->addr, (void*)repinfo->c->socket->addr->ai_addr, repinfo->c->type, repinfo->c->buffer);
+			log_addr(VERB_ALGO, "response to client", &repinfo->client_addr, repinfo->client_addrlen);
+			dt_msg_send_client_response(repinfo->c->dtenv, &repinfo->client_addr, (void*)repinfo->c->socket->addr->ai_addr, repinfo->c->type, repinfo->c->buffer);
 		}
 #endif
 	} else {
@@ -4091,8 +4776,8 @@ comm_point_send_reply(struct comm_reply 
 		 */
 		if(repinfo->c->tcp_parent->dtenv != NULL && repinfo->c->tcp_parent->dtenv->log_client_response_messages) {
 			log_addr(VERB_ALGO, "from local addr", (void*)repinfo->c->socket->addr->ai_addr, repinfo->c->socket->addr->ai_addrlen);
-			log_addr(VERB_ALGO, "response to client", &repinfo->addr, repinfo->addrlen);
-			dt_msg_send_client_response(repinfo->c->tcp_parent->dtenv, &repinfo->addr, (void*)repinfo->c->socket->addr->ai_addr, repinfo->c->type,
+			log_addr(VERB_ALGO, "response to client", &repinfo->client_addr, repinfo->client_addrlen);
+			dt_msg_send_client_response(repinfo->c->tcp_parent->dtenv, &repinfo->client_addr, (void*)repinfo->c->socket->addr->ai_addr, repinfo->c->type,
 				( repinfo->c->tcp_req_info? repinfo->c->tcp_req_info->spool_buffer: repinfo->c->buffer ));
 		}
 #endif
@@ -4116,7 +4801,7 @@ comm_point_send_reply(struct comm_reply 
 	}
 }
 
-void 
+void
 comm_point_drop_reply(struct comm_reply* repinfo)
 {
 	if(!repinfo)
@@ -4140,7 +4825,7 @@ comm_point_drop_reply(struct comm_reply*
 	reclaim_tcp_handler(repinfo->c);
 }
 
-void 
+void
 comm_point_stop_listening(struct comm_point* c)
 {
 	verbose(VERB_ALGO, "comm point stop listening %d", c->fd);
@@ -4152,10 +4837,10 @@ comm_point_stop_listening(struct comm_po
 	}
 }
 
-void 
+void
 comm_point_start_listening(struct comm_point* c, int newfd, int msec)
 {
-	verbose(VERB_ALGO, "comm point start listening %d (%d msec)", 
+	verbose(VERB_ALGO, "comm point start listening %d (%d msec)",
 		c->fd==-1?newfd:c->fd, msec);
 	if(c->type == comm_tcp_accept && !c->tcp_free) {
 		/* no use to start listening no free slots. */
@@ -4239,10 +4924,10 @@ void comm_point_listen_for_rw(struct com
 size_t comm_point_get_mem(struct comm_point* c)
 {
 	size_t s;
-	if(!c) 
+	if(!c)
 		return 0;
 	s = sizeof(*c) + sizeof(*c->ev);
-	if(c->timeout) 
+	if(c->timeout)
 		s += sizeof(*c->timeout);
 	if(c->type == comm_tcp || c->type == comm_local) {
 		s += sizeof(*c->buffer) + sldns_buffer_capacity(c->buffer);
@@ -4261,7 +4946,7 @@ size_t comm_point_get_mem(struct comm_po
 	return s;
 }
 
-struct comm_timer* 
+struct comm_timer*
 comm_timer_create(struct comm_base* base, void (*cb)(void*), void* cb_arg)
 {
 	struct internal_timer *tm = (struct internal_timer*)calloc(1,
@@ -4274,7 +4959,7 @@ comm_timer_create(struct comm_base* base
 	tm->base = base;
 	tm->super.callback = cb;
 	tm->super.cb_arg = cb_arg;
-	tm->ev = ub_event_new(base->eb->base, -1, UB_EV_TIMEOUT, 
+	tm->ev = ub_event_new(base->eb->base, -1, UB_EV_TIMEOUT,
 		comm_timer_callback, &tm->super);
 	if(tm->ev == NULL) {
 		log_err("timer_create: event_base_set failed.");
@@ -4284,7 +4969,7 @@ comm_timer_create(struct comm_base* base
 	return &tm->super;
 }
 
-void 
+void
 comm_timer_disable(struct comm_timer* timer)
 {
 	if(!timer)
@@ -4293,7 +4978,7 @@ comm_timer_disable(struct comm_timer* ti
 	timer->ev_timer->enabled = 0;
 }
 
-void 
+void
 comm_timer_set(struct comm_timer* timer, struct timeval* tv)
 {
 	log_assert(tv);
@@ -4305,7 +4990,7 @@ comm_timer_set(struct comm_timer* timer,
 	timer->ev_timer->enabled = 1;
 }
 
-void 
+void
 comm_timer_delete(struct comm_timer* timer)
 {
 	if(!timer)
@@ -4318,7 +5003,7 @@ comm_timer_delete(struct comm_timer* tim
 	free(timer->ev_timer);
 }
 
-void 
+void
 comm_timer_callback(int ATTR_UNUSED(fd), short event, void* arg)
 {
 	struct comm_timer* tm = (struct comm_timer*)arg;
@@ -4330,19 +5015,19 @@ comm_timer_callback(int ATTR_UNUSED(fd),
 	(*tm->callback)(tm->cb_arg);
 }
 
-int 
+int
 comm_timer_is_set(struct comm_timer* timer)
 {
 	return (int)timer->ev_timer->enabled;
 }
 
-size_t 
+size_t
 comm_timer_get_mem(struct comm_timer* ATTR_UNUSED(timer))
 {
 	return sizeof(struct internal_timer);
 }
 
-struct comm_signal* 
+struct comm_signal*
 comm_signal_create(struct comm_base* base,
         void (*callback)(int, void*), void* cb_arg)
 {
@@ -4359,7 +5044,7 @@ comm_signal_create(struct comm_base* bas
 	return com;
 }
 
-void 
+void
 comm_signal_callback(int sig, short event, void* arg)
 {
 	struct comm_signal* comsig = (struct comm_signal*)arg;
@@ -4370,10 +5055,10 @@ comm_signal_callback(int sig, short even
 	(*comsig->callback)(sig, comsig->cb_arg);
 }
 
-int 
+int
 comm_signal_bind(struct comm_signal* comsig, int sig)
 {
-	struct internal_signal* entry = (struct internal_signal*)calloc(1, 
+	struct internal_signal* entry = (struct internal_signal*)calloc(1,
 		sizeof(struct internal_signal));
 	if(!entry) {
 		log_err("malloc failed");
@@ -4400,7 +5085,7 @@ comm_signal_bind(struct comm_signal* com
 	return 1;
 }
 
-void 
+void
 comm_signal_delete(struct comm_signal* comsig)
 {
 	struct internal_signal* p, *np;

Index: src/external/bsd/unbound/include/config.h
diff -u src/external/bsd/unbound/include/config.h:1.11 src/external/bsd/unbound/include/config.h:1.12
--- src/external/bsd/unbound/include/config.h:1.11	Tue May 23 16:07:21 2023
+++ src/external/bsd/unbound/include/config.h	Sat Feb 17 13:31:19 2024
@@ -142,7 +142,7 @@
 
 /* Define to 1 if you have the declaration of `reallocarray', and to 0 if you
    don't. */
-#define HAVE_DECL_REALLOCARRAY 0
+#define HAVE_DECL_REALLOCARRAY 1
 
 /* Define to 1 if you have the declaration of `redisConnect', and to 0 if you
    don't. */
@@ -225,7 +225,7 @@
 
 /* Define to 1 if you have the `EVP_default_properties_is_fips_enabled'
    function. */
-/* #undef HAVE_EVP_DEFAULT_PROPERTIES_IS_FIPS_ENABLED */
+#define HAVE_EVP_DEFAULT_PROPERTIES_IS_FIPS_ENABLED 1
 
 /* Define to 1 if you have the `EVP_DigestVerify' function. */
 #define HAVE_EVP_DIGESTVERIFY 1
@@ -237,7 +237,7 @@
 #define HAVE_EVP_ENCRYPTINIT_EX 1
 
 /* Define to 1 if you have the `EVP_MAC_CTX_set_params' function. */
-/* #undef HAVE_EVP_MAC_CTX_SET_PARAMS */
+#define HAVE_EVP_MAC_CTX_SET_PARAMS 1
 
 /* Define to 1 if you have the `EVP_MD_CTX_new' function. */
 #define HAVE_EVP_MD_CTX_NEW 1
@@ -267,7 +267,7 @@
 #define HAVE_FCNTL 1
 
 /* Define to 1 if you have the `FIPS_mode' function. */
-#define HAVE_FIPS_MODE 1
+/* #undef HAVE_FIPS_MODE */
 
 /* Define to 1 if you have the `fork' function. */
 #define HAVE_FORK 1
@@ -299,6 +299,9 @@
 /* Define to 1 if you have the `getrlimit' function. */
 #define HAVE_GETRLIMIT 1
 
+/* Define to 1 if you have the `gettid' function. */
+/* #undef HAVE_GETTID */
+
 /* Define to 1 if you have the `glob' function. */
 #define HAVE_GLOB 1
 
@@ -362,6 +365,9 @@
 /* Define if we have LibreSSL */
 /* #undef HAVE_LIBRESSL */
 
+/* Define to 1 if you have the <linux/net_tstamp.h> header file. */
+/* #undef HAVE_LINUX_NET_TSTAMP_H */
+
 /* Define to 1 if you have the `localtime_r' function. */
 #define HAVE_LOCALTIME_R 1
 
@@ -423,7 +429,7 @@
 #define HAVE_OPENSSL_CONF_H 1
 
 /* Define to 1 if you have the <openssl/core_names.h> header file. */
-/* #undef HAVE_OPENSSL_CORE_NAMES_H */
+#define HAVE_OPENSSL_CORE_NAMES_H 1
 
 /* Define to 1 if you have the <openssl/dh.h> header file. */
 #define HAVE_OPENSSL_DH_H 1
@@ -444,7 +450,7 @@
 #define HAVE_OPENSSL_INIT_SSL 1
 
 /* Define to 1 if you have the <openssl/param_build.h> header file. */
-/* #undef HAVE_OPENSSL_PARAM_BUILD_H */
+#define HAVE_OPENSSL_PARAM_BUILD_H 1
 
 /* Define to 1 if you have the <openssl/rand.h> header file. */
 #define HAVE_OPENSSL_RAND_H 1
@@ -456,7 +462,13 @@
 #define HAVE_OPENSSL_SSL_H 1
 
 /* Define to 1 if you have the `OSSL_PARAM_BLD_new' function. */
-/* #undef HAVE_OSSL_PARAM_BLD_NEW */
+#define HAVE_OSSL_PARAM_BLD_NEW 1
+
+/* Define to 1 if you have the `poll' function. */
+#define HAVE_POLL 1
+
+/* Define to 1 if you have the <poll.h> header file. */
+#define HAVE_POLL_H 1
 
 /* Define if you have POSIX threads libraries and header files. */
 #define HAVE_PTHREAD 1
@@ -553,7 +565,7 @@
 
 /* Define to 1 if you have the `SSL_CTX_set_tlsext_ticket_key_evp_cb'
    function. */
-/* #undef HAVE_SSL_CTX_SET_TLSEXT_TICKET_KEY_EVP_CB */
+#define HAVE_SSL_CTX_SET_TLSEXT_TICKET_KEY_EVP_CB 1
 
 /* Define to 1 if you have the `SSL_get0_alpn_selected' function. */
 #define HAVE_SSL_GET0_ALPN_SELECTED 1
@@ -562,7 +574,7 @@
 #define HAVE_SSL_GET0_PEERNAME 1
 
 /* Define to 1 if you have the `SSL_get1_peer_certificate' function. */
-/* #undef HAVE_SSL_GET1_PEER_CERTIFICATE */
+#define HAVE_SSL_GET1_PEER_CERTIFICATE 1
 
 /* Define to 1 if you have the `SSL_set1_host' function. */
 #define HAVE_SSL_SET1_HOST 1
@@ -761,7 +773,7 @@
 #define PACKAGE_NAME "unbound"
 
 /* Define to the full name and version of this package. */
-#define PACKAGE_STRING "unbound 1.16.3"
+#define PACKAGE_STRING "unbound 1.19.1"
 
 /* Define to the one symbol short name of this package. */
 #define PACKAGE_TARNAME "unbound"
@@ -770,7 +782,7 @@
 #define PACKAGE_URL ""
 
 /* Define to the version of this package. */
-#define PACKAGE_VERSION "1.16.3"
+#define PACKAGE_VERSION "1.19.1"
 
 /* default pidfile location */
 #define PIDFILE "/var/run/unbound.pid"
@@ -793,7 +805,7 @@
 #define ROOT_CERT_FILE CHROOT_DIR "/etc/unbound/icannbundle.pem"
 
 /* version number for resource files */
-#define RSRC_PACKAGE_VERSION 1,16,3,0
+#define RSRC_PACKAGE_VERSION 1,19,1,0
 
 /* Directory to chdir to */
 #define RUN_DIR CHROOT_DIR "/etc/unbound"
@@ -801,12 +813,31 @@
 /* Shared data */
 #define SHARE_DIR CHROOT_DIR "/etc/unbound"
 
+#ifdef _LP64
+/* The size of `pthread_t', as computed by sizeof. */
+#define SIZEOF_PTHREAD_T 8
+
 /* The size of `size_t', as computed by sizeof. */
 #define SIZEOF_SIZE_T 8
+#else
+/* The size of `pthread_t', as computed by sizeof. */
+#define SIZEOF_PTHREAD_T 4
+
+/* The size of `size_t', as computed by sizeof. */
+#define SIZEOF_SIZE_T 4
+#endif
 
 /* The size of `time_t', as computed by sizeof. */
 #define SIZEOF_TIME_T 8
 
+#ifdef _LP64
+/* The size of `unsigned long', as computed by sizeof. */
+#define SIZEOF_UNSIGNED_LONG 8
+#else
+/* The size of `unsigned long', as computed by sizeof. */
+#define SIZEOF_UNSIGNED_LONG 4
+#endif
+
 /* define if (v)snprintf does not return length needed, (but length used) */
 /* #undef SNPRINTF_RET_BROKEN */
 
@@ -879,6 +910,14 @@
 /* Define if you enable libevent */
 #define USE_LIBEVENT 1
 
+/* Define this to enable use of /proc/sys/net/ipv4/ip_local_port_range as a
+   default outgoing port range. This is only for the libunbound on Linux and
+   does not affect unbound resolving daemon itself. This may severely limit
+   the number of available outgoing ports and thus decrease randomness. Define
+   this only when the target system restricts (e.g. some of SELinux enabled
+   distributions) the use of non-ephemeral ports. */
+/* #undef USE_LINUX_IP_LOCAL_PORT_RANGE */
+
 /* Define if you want to use internal select based events */
 /* #undef USE_MINI_EVENT */
 
@@ -965,6 +1004,9 @@
    this defined. */
 /* #undef _POSIX_1_SOURCE */
 
+/* Define to 1 if you need to in order for `stat' and other things to work. */
+/* #undef _POSIX_SOURCE */
+
 /* defined to use gcc ansi snprintf and sscanf that understands %lld when
    compiled for windows. */
 /* #undef __USE_MINGW_ANSI_STDIO */
@@ -1046,15 +1088,15 @@
 
 #if defined(OMITTED__D_GNU_SOURCE) && !defined(_GNU_SOURCE)
 #define _GNU_SOURCE 1
-#endif 
+#endif
 
 #if defined(OMITTED__D_BSD_SOURCE) && !defined(_BSD_SOURCE)
 #define _BSD_SOURCE 1
-#endif 
+#endif
 
 #if defined(OMITTED__D_DEFAULT_SOURCE) && !defined(_DEFAULT_SOURCE)
 #define _DEFAULT_SOURCE 1
-#endif 
+#endif
 
 #if defined(OMITTED__D__EXTENSIONS__) && !defined(__EXTENSIONS__)
 #define __EXTENSIONS__ 1
@@ -1062,23 +1104,23 @@
 
 #if defined(OMITTED__D_POSIX_C_SOURCE_200112) && !defined(_POSIX_C_SOURCE)
 #define _POSIX_C_SOURCE 200112
-#endif 
+#endif
 
 #if defined(OMITTED__D_XOPEN_SOURCE_600) && !defined(_XOPEN_SOURCE)
 #define _XOPEN_SOURCE 600
-#endif 
+#endif
 
 #if defined(OMITTED__D_XOPEN_SOURCE_EXTENDED_1) && !defined(_XOPEN_SOURCE_EXTENDED)
 #define _XOPEN_SOURCE_EXTENDED 1
-#endif 
+#endif
 
 #if defined(OMITTED__D_ALL_SOURCE) && !defined(_ALL_SOURCE)
 #define _ALL_SOURCE 1
-#endif 
+#endif
 
 #if defined(OMITTED__D_LARGEFILE_SOURCE_1) && !defined(_LARGEFILE_SOURCE)
 #define _LARGEFILE_SOURCE 1
-#endif 
+#endif
 
 
 
@@ -1162,7 +1204,7 @@
 #endif
 
 
- 
+
 #ifdef HAVE_ATTR_FORMAT
 #  define ATTR_FORMAT(archetype, string_index, first_to_check) \
     __attribute__ ((format (archetype, string_index, first_to_check)))
@@ -1272,7 +1314,7 @@ void* reallocarray(void *ptr, size_t nme
 #ifdef HAVE_WINSOCK2_H
 #define FD_SET_T (u_int)
 #else
-#define FD_SET_T 
+#define FD_SET_T
 #endif
 
 

Index: src/external/bsd/unbound/lib/libunbound/Makefile
diff -u src/external/bsd/unbound/lib/libunbound/Makefile:1.8 src/external/bsd/unbound/lib/libunbound/Makefile:1.9
--- src/external/bsd/unbound/lib/libunbound/Makefile:1.8	Tue May  9 10:31:55 2023
+++ src/external/bsd/unbound/lib/libunbound/Makefile	Sat Feb 17 13:31:19 2024
@@ -1,4 +1,4 @@
-# $NetBSD: Makefile,v 1.8 2023/05/09 14:31:55 christos Exp $
+# $NetBSD: Makefile,v 1.9 2024/02/17 18:31:19 christos Exp $
 
 .include <bsd.init.mk>
 
@@ -68,19 +68,23 @@ outside_network.c \
 packed_rrset.c \
 parse.c \
 parseutil.c \
+proxy_protocol.c \
 random.c \
 rbtree.c \
 regional.c \
 respip.c \
+rfc_1982.c \
 rpz.c \
 rrdef.c \
 rrset.c \
 rtt.c \
 sbuffer.c \
+siphash.c \
 slabhash.c \
 str2wire.c \
 tcp_conn_limit.c \
 timehist.c \
+timeval_func.c \
 tube.c \
 ub_event_pluggable.c \
 val_anchor.c \

Index: src/external/bsd/unbound/lib/libunbound/shlib_version
diff -u src/external/bsd/unbound/lib/libunbound/shlib_version:1.5 src/external/bsd/unbound/lib/libunbound/shlib_version:1.6
--- src/external/bsd/unbound/lib/libunbound/shlib_version:1.5	Wed Sep  6 08:48:15 2023
+++ src/external/bsd/unbound/lib/libunbound/shlib_version	Sat Feb 17 13:31:19 2024
@@ -1,4 +1,4 @@
-#	$NetBSD: shlib_version,v 1.5 2023/09/06 12:48:15 riastradh Exp $
+#	$NetBSD: shlib_version,v 1.6 2024/02/17 18:31:19 christos Exp $
 #
-major=8
+major=9
 minor=0

Reply via email to