aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorCy Schubert <cy@FreeBSD.org>2021-12-03 06:11:04 +0000
committerCy Schubert <cy@FreeBSD.org>2021-12-09 18:50:23 +0000
commit19109e76d1ebcc561e412073ce0f427cc0122f76 (patch)
tree116240983198865b089cee1691d7fe58f6eb73a9
parent5542dcf8dcf67b84181e779fcfcf4b41e30e95bf (diff)
unbount: Vendor import 1.14.0rc1
This vendor import was requested by glebius@ as it should fix unbound crashes. Reported by: glebius (cherry picked from commit 24e365220007c415f495cf8dcb228ece6002b8b7)
-rw-r--r--contrib/unbound/.gitattributes1
-rw-r--r--contrib/unbound/.github/FUNDING.yml2
-rw-r--r--contrib/unbound/.github/ISSUE_TEMPLATE/bug_report.md41
-rw-r--r--contrib/unbound/.github/ISSUE_TEMPLATE/feature_request.md31
-rw-r--r--contrib/unbound/.github/workflows/analysis_ports.yml346
-rw-r--r--contrib/unbound/.github/workflows/ci.yml21
-rw-r--r--contrib/unbound/.travis.yml380
-rw-r--r--contrib/unbound/Makefile.in5
-rw-r--r--contrib/unbound/README-Travis.md2
-rw-r--r--contrib/unbound/acx_nlnetlabs.m466
-rw-r--r--contrib/unbound/cachedb/cachedb.c2
-rw-r--r--contrib/unbound/config.h.in6
-rwxr-xr-xcontrib/unbound/config.sub21
-rwxr-xr-xcontrib/unbound/configure130
-rw-r--r--contrib/unbound/configure.ac43
-rw-r--r--contrib/unbound/contrib/Dockerfile.tests11
-rw-r--r--contrib/unbound/contrib/drop2rpz2
-rw-r--r--contrib/unbound/contrib/unbound.service.in3
-rw-r--r--contrib/unbound/daemon/daemon.c3
-rw-r--r--contrib/unbound/daemon/remote.c2
-rw-r--r--contrib/unbound/daemon/stats.c2
-rw-r--r--contrib/unbound/daemon/unbound.c1
-rw-r--r--contrib/unbound/daemon/worker.c82
-rw-r--r--contrib/unbound/dns64/dns64.c13
-rw-r--r--contrib/unbound/dnscrypt/dnscrypt.c4
-rw-r--r--contrib/unbound/dnscrypt/dnscrypt.h4
-rw-r--r--contrib/unbound/dnstap/dtstream.c6
-rw-r--r--contrib/unbound/dnstap/unbound-dnstap-socket.c12
-rw-r--r--contrib/unbound/doc/Changelog164
-rw-r--r--contrib/unbound/doc/README2
-rw-r--r--contrib/unbound/doc/README.tests8
-rw-r--r--contrib/unbound/doc/example.conf.in17
-rw-r--r--contrib/unbound/doc/libunbound.3.in4
-rw-r--r--contrib/unbound/doc/unbound-anchor.8.in2
-rw-r--r--contrib/unbound/doc/unbound-checkconf.8.in2
-rw-r--r--contrib/unbound/doc/unbound-control.8.in6
-rw-r--r--contrib/unbound/doc/unbound-host.1.in2
-rw-r--r--contrib/unbound/doc/unbound.8.in4
-rw-r--r--contrib/unbound/doc/unbound.conf.5.in95
-rw-r--r--contrib/unbound/doc/unbound.doxygen6
-rw-r--r--contrib/unbound/edns-subnet/edns-subnet.h2
-rw-r--r--contrib/unbound/edns-subnet/subnetmod.c2
-rw-r--r--contrib/unbound/ipsecmod/ipsecmod.c2
-rw-r--r--contrib/unbound/ipsecmod/ipsecmod.h2
-rw-r--r--contrib/unbound/iterator/iter_delegpt.c1
-rw-r--r--contrib/unbound/iterator/iter_delegpt.h2
-rw-r--r--contrib/unbound/iterator/iter_fwd.c2
-rw-r--r--contrib/unbound/iterator/iter_hints.c4
-rw-r--r--contrib/unbound/iterator/iter_utils.c152
-rw-r--r--contrib/unbound/iterator/iter_utils.h7
-rw-r--r--contrib/unbound/iterator/iterator.c76
-rw-r--r--contrib/unbound/iterator/iterator.h5
-rw-r--r--contrib/unbound/libunbound/context.c2
-rw-r--r--contrib/unbound/libunbound/context.h29
-rw-r--r--contrib/unbound/libunbound/libunbound.c4
-rw-r--r--contrib/unbound/libunbound/libworker.c10
-rw-r--r--contrib/unbound/libunbound/unbound-event.h2
-rw-r--r--contrib/unbound/libunbound/unbound.h32
-rw-r--r--contrib/unbound/libunbound/worker.h10
-rw-r--r--contrib/unbound/respip/respip.c75
-rw-r--r--contrib/unbound/respip/respip.h3
-rw-r--r--contrib/unbound/services/authzone.c215
-rw-r--r--contrib/unbound/services/authzone.h5
-rw-r--r--contrib/unbound/services/cache/rrset.h4
-rw-r--r--contrib/unbound/services/listen_dnsport.c71
-rw-r--r--contrib/unbound/services/listen_dnsport.h5
-rw-r--r--contrib/unbound/services/localzone.c35
-rw-r--r--contrib/unbound/services/localzone.h6
-rw-r--r--contrib/unbound/services/mesh.c95
-rw-r--r--contrib/unbound/services/outbound_list.h2
-rw-r--r--contrib/unbound/services/outside_network.c11
-rw-r--r--contrib/unbound/services/rpz.c1743
-rw-r--r--contrib/unbound/services/rpz.h54
-rw-r--r--contrib/unbound/sldns/parseutil.h2
-rw-r--r--contrib/unbound/sldns/str2wire.c4
-rw-r--r--contrib/unbound/sldns/wire2str.h2
-rw-r--r--contrib/unbound/smallapp/unbound-anchor.c8
-rw-r--r--contrib/unbound/smallapp/unbound-checkconf.c62
-rw-r--r--contrib/unbound/smallapp/unbound-control.c2
-rw-r--r--contrib/unbound/smallapp/worker_cb.c4
-rw-r--r--contrib/unbound/testdata/auth_zonemd_xfr_chain_keyinxfr.rpl315
-rw-r--r--contrib/unbound/testdata/fwd_error_retries.rpl27
-rw-r--r--contrib/unbound/testdata/fwd_udp_with_tcp_upstream.tdir/fwd_udp_with_tcp_upstream.conf20
-rw-r--r--contrib/unbound/testdata/fwd_udp_with_tcp_upstream.tdir/fwd_udp_with_tcp_upstream.dsc16
-rw-r--r--contrib/unbound/testdata/fwd_udp_with_tcp_upstream.tdir/fwd_udp_with_tcp_upstream.post10
-rw-r--r--contrib/unbound/testdata/fwd_udp_with_tcp_upstream.tdir/fwd_udp_with_tcp_upstream.pre31
-rw-r--r--contrib/unbound/testdata/fwd_udp_with_tcp_upstream.tdir/fwd_udp_with_tcp_upstream.test35
-rw-r--r--contrib/unbound/testdata/fwd_udp_with_tcp_upstream.tdir/fwd_udp_with_tcp_upstream.testns25
-rw-r--r--contrib/unbound/testdata/http_user_agent.tdir/http_user_agent.test10
-rw-r--r--contrib/unbound/testdata/rpz_clientip.rpl264
-rw-r--r--contrib/unbound/testdata/rpz_nsdname.rpl390
-rw-r--r--contrib/unbound/testdata/rpz_nsip.rpl408
-rw-r--r--contrib/unbound/testdata/rpz_qname_tcponly.rpl117
-rw-r--r--contrib/unbound/testdata/rpz_respip_tcponly.rpl207
-rw-r--r--contrib/unbound/testdata/stub_udp_with_tcp_upstream.tdir/stub_udp_with_tcp_upstream.conf19
-rw-r--r--contrib/unbound/testdata/stub_udp_with_tcp_upstream.tdir/stub_udp_with_tcp_upstream.dsc16
-rw-r--r--contrib/unbound/testdata/stub_udp_with_tcp_upstream.tdir/stub_udp_with_tcp_upstream.post10
-rw-r--r--contrib/unbound/testdata/stub_udp_with_tcp_upstream.tdir/stub_udp_with_tcp_upstream.pre35
-rw-r--r--contrib/unbound/testdata/stub_udp_with_tcp_upstream.tdir/stub_udp_with_tcp_upstream.test37
-rw-r--r--contrib/unbound/testdata/stub_udp_with_tcp_upstream.tdir/stub_udp_with_tcp_upstream.testns48
-rw-r--r--contrib/unbound/testdata/svcb.tdir/svcb.test2
-rw-r--r--contrib/unbound/util/config_file.c3
-rw-r--r--contrib/unbound/util/config_file.h6
-rw-r--r--contrib/unbound/util/configlexer.lex3
-rw-r--r--contrib/unbound/util/configparser.y481
-rw-r--r--contrib/unbound/util/data/msgencode.c20
-rw-r--r--contrib/unbound/util/data/msgparse.c150
-rw-r--r--contrib/unbound/util/data/msgparse.h23
-rw-r--r--contrib/unbound/util/data/msgreply.c67
-rw-r--r--contrib/unbound/util/data/msgreply.h27
-rw-r--r--contrib/unbound/util/data/packed_rrset.h8
-rw-r--r--contrib/unbound/util/edns.c50
-rw-r--r--contrib/unbound/util/edns.h12
-rw-r--r--contrib/unbound/util/fptr_wlist.c2
-rw-r--r--contrib/unbound/util/fptr_wlist.h2
-rw-r--r--contrib/unbound/util/iana_ports.inc1
-rw-r--r--contrib/unbound/util/mini_event.c9
-rw-r--r--contrib/unbound/util/module.h5
-rw-r--r--contrib/unbound/util/net_help.c25
-rw-r--r--contrib/unbound/util/netevent.c63
-rw-r--r--contrib/unbound/util/netevent.h2
-rw-r--r--contrib/unbound/util/regional.c2
-rw-r--r--contrib/unbound/util/shm_side/shm_main.c2
-rw-r--r--contrib/unbound/util/tube.c6
-rw-r--r--contrib/unbound/util/ub_event.c2
-rw-r--r--contrib/unbound/validator/autotrust.c4
-rw-r--r--contrib/unbound/validator/validator.c4
-rw-r--r--contrib/unbound/validator/validator.h2
128 files changed, 5359 insertions, 1972 deletions
diff --git a/contrib/unbound/.gitattributes b/contrib/unbound/.gitattributes
deleted file mode 100644
index 6414a0ab5302..000000000000
--- a/contrib/unbound/.gitattributes
+++ /dev/null
@@ -1 +0,0 @@
-testdata/*.[0-9] linguist-documentation
diff --git a/contrib/unbound/.github/FUNDING.yml b/contrib/unbound/.github/FUNDING.yml
deleted file mode 100644
index 2a357c0c7778..000000000000
--- a/contrib/unbound/.github/FUNDING.yml
+++ /dev/null
@@ -1,2 +0,0 @@
-github: [NLnetLabs]
-custom: ['https://nlnetlabs.nl/funding/']
diff --git a/contrib/unbound/.github/ISSUE_TEMPLATE/bug_report.md b/contrib/unbound/.github/ISSUE_TEMPLATE/bug_report.md
deleted file mode 100644
index 35d7ee94f9da..000000000000
--- a/contrib/unbound/.github/ISSUE_TEMPLATE/bug_report.md
+++ /dev/null
@@ -1,41 +0,0 @@
----
-name: Bug report
-about: Create a report to help us improve Unbound
-title: ''
-labels: ''
-assignees: ''
-
----
-
-<!--
-Thanks for taking the time to report an issue!
-
-Before continuing please make sure that you checked the existing (opened and closed) issues and pull requests to avoid opening a duplicate issue. We would rather prefer to add the information to the existing one. If you are able, feel free to reopen the closed issue afterwards. If not, please create a new issue linking to the old one.
-
-If you rather have a support question and you need guidance on running/configuring Unbound, please refrain from opening an issue and use the community support mailing list instead (https://www.nlnetlabs.nl/support/mailing-lists/).
-We would like to keep GitHub issues for possible bugs and feature requests only.
-
-If you are unsure whether an issue is a bug or not, feel free to reach out to mailing list users or open an issue here.
-
-If you are opening an issue, please complete as much of the following sections as possible to give us a better understanding of your situation.
--->
-
-**Describe the bug**
-A clear and concise description of what the bug is.
-
-**To reproduce**
-Steps to reproduce the behavior:
-1.
-2.
-3.
-
-**Expected behavior**
-A clear and concise description of what you expected to happen.
-
-**System:**
- - Unbound version:
- - OS:
- - `unbound -V` output:
-
-**Additional information**
-Add any other information that you may have gathered about the issue here.
diff --git a/contrib/unbound/.github/ISSUE_TEMPLATE/feature_request.md b/contrib/unbound/.github/ISSUE_TEMPLATE/feature_request.md
deleted file mode 100644
index e9ca08b7ab65..000000000000
--- a/contrib/unbound/.github/ISSUE_TEMPLATE/feature_request.md
+++ /dev/null
@@ -1,31 +0,0 @@
----
-name: Feature request
-about: Suggest an idea for Unbound
-title: "[FR]"
-labels: ''
-assignees: ''
-
----
-
-<!--
-Thanks for taking the time to report an issue!
-
-Before continuing please make sure that you checked the existing (opened and closed) issues and pull requests to avoid opening a duplicate issue. We would rather prefer to add the information to the existing one. If you are able, feel free to reopen the closed issue afterwards. If not, please create a new issue linking to the old one.
-
-If you rather have a support question and you need guidance on running/configuring Unbound, please refrain from opening an issue and use the community support mailing list instead (https://www.nlnetlabs.nl/support/mailing-lists/).
-We would like to keep GitHub issues for possible bugs and feature requests only.
-
-If you are unsure whether an issue is a bug or not, feel free to reach out to mailing list users or open an issue here.
-
-If you are opening an issue, please complete as much of the following sections as possible to give us a better understanding of your situation.
--->
-
-**Current behavior**
-Is there a current behavior that the feature relates to?
-If yes, would you wish the current behavior to change?
-
-**Describe the desired feature**
-A clear and concise description of what the feature should be.
-
-**Potential use-case**
-Describe how you see this feature being useful to other Unbound users.
diff --git a/contrib/unbound/.github/workflows/analysis_ports.yml b/contrib/unbound/.github/workflows/analysis_ports.yml
deleted file mode 100644
index fbbdd80185a9..000000000000
--- a/contrib/unbound/.github/workflows/analysis_ports.yml
+++ /dev/null
@@ -1,346 +0,0 @@
-name: Analysis and Ports
-
-on:
- workflow_dispatch:
- inputs:
- start:
- description: 'Start analysis and port workflow'
- default: 'yes'
- required: true
-
-jobs:
- build:
- runs-on: ${{ matrix.os }}
- strategy:
- matrix:
- include:
- - name: GCC on Linux
- os: ubuntu-latest
- config: "--enable-debug --disable-flto"
- make_test: "yes"
- - name: Clang-analyzer
- os: ubuntu-latest
- config: "CC=clang --enable-debug --disable-flto --disable-static"
- make_test: "yes"
- clang_analysis: "yes"
- - name: libevent
- os: ubuntu-latest
- install_libevent: "yes"
- config: "CC=clang --enable-debug --disable-flto --with-libevent --disable-static"
- make_test: "yes"
- clang_analysis: "yes"
- - name: OS X
- os: macos-latest
- install_expat: "yes"
- config: "--enable-debug --disable-flto --with-ssl=/usr/local/opt/openssl --with-libexpat=/usr/local/opt/expat"
- make_test: "yes"
- - name: Clang on OS X
- os: macos-latest
- install_expat: "yes"
- config: "CC=clang --enable-debug --disable-flto --with-ssl=/usr/local/opt/openssl --with-libexpat=/usr/local/opt/expat --disable-static"
- make_test: "yes"
- clang_analysis: "yes"
- - name: ubsan (gcc undefined behaviour sanitizer)
- os: ubuntu-latest
- config: 'CFLAGS="-DNDEBUG -g2 -O3 -fsanitize=undefined -fno-sanitize-recover=all" --disable-flto --disable-static'
- make_test: "yes"
- - name: asan (gcc address sanitizer)
- os: ubuntu-latest
- config: 'CFLAGS="-DNDEBUG -g2 -O3 -fsanitize=address" --disable-flto --disable-static'
- make_test: "yes"
- - name: Apple iPhone on iOS, armv7
- os: macos-latest
- AUTOTOOLS_HOST: armv7-apple-ios
- OPENSSL_HOST: ios-cross
- IOS_SDK: iPhoneOS
- IOS_CPU: armv7s
- test_ios: "yes"
- config: "no"
- make: "no"
- - name: Apple iPhone on iOS, arm64
- os: macos-latest
- AUTOTOOLS_HOST: aarch64-apple-ios
- OPENSSL_HOST: ios64-cross
- IOS_SDK: iPhoneOS
- IOS_CPU: arm64
- test_ios: "yes"
- config: "no"
- make: "no"
- - name: Apple TV on iOS, arm64
- os: macos-latest
- AUTOTOOLS_HOST: aarch64-apple-ios
- OPENSSL_HOST: ios64-cross
- IOS_SDK: AppleTVOS
- IOS_CPU: arm64
- test_ios: "yes"
- config: "no"
- make: "no"
- - name: Apple Watch on iOS, armv7
- os: macos-latest
- AUTOTOOLS_HOST: armv7-apple-ios
- OPENSSL_HOST: ios-cross
- IOS_SDK: WatchOS
- IOS_CPU: armv7k
- test_ios: "yes"
- config: "no"
- make: "no"
- - name: iPhoneSimulator on OS X, i386
- os: macos-latest
- AUTOTOOLS_HOST: i386-apple-ios
- OPENSSL_HOST: iphoneos-cross
- IOS_SDK: iPhoneSimulator
- IOS_CPU: i386
- test_ios: "yes"
- config: "no"
- make: "no"
- - name: iPhoneSimulator on OS X, x86_64
- os: macos-latest
- AUTOTOOLS_HOST: x86_64-apple-ios
- OPENSSL_HOST: iphoneos-cross
- IOS_SDK: iPhoneSimulator
- IOS_CPU: x86_64
- test_ios: "yes"
- config: "no"
- make: "no"
- - name: AppleTVSimulator on OS X, x86_64
- os: macos-latest
- AUTOTOOLS_HOST: x86_64-apple-ios
- OPENSSL_HOST: iphoneos-cross
- IOS_SDK: AppleTVSimulator
- IOS_CPU: x86_64
- test_ios: "yes"
- config: "no"
- make: "no"
- - name: WatchSimulator on OS X, i386
- os: macos-latest
- AUTOTOOLS_HOST: i386-apple-ios
- OPENSSL_HOST: iphoneos-cross
- IOS_SDK: WatchSimulator
- IOS_CPU: i386
- test_ios: "yes"
- config: "no"
- make: "no"
- - name: Android armv7a
- os: ubuntu-latest
- AUTOTOOLS_HOST: armv7a-linux-androidabi
- OPENSSL_HOST: android-arm
- ANDROID_CPU: armv7a
- ANDROID_API: 23
- test_android: "yes"
- config: "no"
- make: "no"
- - name: Android aarch64
- os: ubuntu-latest
- AUTOTOOLS_HOST: aarch64-linux-android
- OPENSSL_HOST: android-arm64
- ANDROID_CPU: aarch64
- ANDROID_API: 23
- test_android: "yes"
- config: "no"
- make: "no"
- - name: Android x86
- os: ubuntu-latest
- AUTOTOOLS_HOST: i686-linux-android
- OPENSSL_HOST: android-x86
- ANDROID_CPU: x86
- ANDROID_API: 23
- test_android: "yes"
- config: "no"
- make: "no"
- - name: Android x86_64
- os: ubuntu-latest
- AUTOTOOLS_HOST: x86_64-linux-android
- OPENSSL_HOST: android-x86_64
- ANDROID_CPU: x86_64
- ANDROID_API: 23
- test_android: "yes"
- config: "no"
- make: "no"
- - name: Windows
- os: windows-latest
- test_windows: "yes"
- config: "no"
- make: "no"
-
- steps:
- - uses: actions/checkout@v2
- with:
- submodules: false
- - name: test_windows
- if: ${{ matrix.test_windows == 'yes' }}
- shell: bash
- run: |
- export unboundpath=`pwd`
- echo unboundpath=${unboundpath}
- cd ..
- export prepath=`pwd`
- echo prepath=${prepath}
- #echo "curl cpanm"
- #curl -L -k -s -S -o cpanm https://cpanmin.us/
- #echo "perl cpanm Pod::Usage"
- #perl cpanm Pod::Usage
- mkdir openssl
- echo "curl openssl"
- curl -L -k -s -S -o openssl-1.1.1j.tar.gz https://www.openssl.org/source/openssl-1.1.1j.tar.gz
- tar xzf openssl-1.1.1j.tar.gz
- cd openssl-1.1.1j
- # remove pod::Usage because we do not need -help or -man output
- # from the Configure script
- echo "Fixup ./Configure by removing use Pod::Usage require"
- sed -e 's/use Pod::Usage//' < Configure > Configure.fix
- echo "./Configure.fix no-shared no-asm -DOPENSSL_NO_CAPIENG mingw64 --prefix=\""$prepath/openssl\"""
- ./Configure.fix no-shared no-asm -DOPENSSL_NO_CAPIENG mingw64 --prefix="$prepath/openssl"
- # make the libs only, build faster
- echo "make build_libs"
- #make
- make build_libs
- mv Makefile Makefile.orig
- # fixup \\ in the installtop to /.
- echo "fixup INSTALLTOP"
- sed -e 's?^INSTALLTOP=.*$?INSTALLTOP='"$prepath"'/openssl?' < Makefile.orig > Makefile
- # install the includes and libs only, build faster
- echo "make install_dev"
- #make install_sw
- make install_dev
- cd ..
- mkdir expat
- echo "curl expat"
- curl -L -k -s -S -o expat-2.2.10.tar.gz https://github.com/libexpat/libexpat/releases/download/R_2_2_10/expat-2.2.10.tar.gz
- tar xzf expat-2.2.10.tar.gz
- cd expat-2.2.10
- echo "./configure SHELL=/usr/bin/bash CONFIG_SHELL=/usr/bin/bash --prefix=\"$prepath/expat\" --exec-prefix=\"$prepath/expat\" --bindir=\"$prepath/expat/bin\" --includedir=\"$prepath/expat/include\" --mandir=\"$prepath/expat/man\" --libdir=\"$prepath/expat/lib\""
- ./configure SHELL=/usr/bin/bash CONFIG_SHELL=/usr/bin/bash --prefix="$prepath/expat" --exec-prefix="$prepath/expat" --bindir="$prepath/expat/bin" --includedir="$prepath/expat/include" --mandir="$prepath/expat/man" --libdir="$prepath/expat/lib"
- # fixup SHELL is treated specially, but SHELZZ is not by make.
- echo "Fixup Makefiles by renaming SHELL to SHELLZZ"
- mv Makefile Makefile.orig
- sed -e 's/SHELL/SHELLZZ/g' < Makefile.orig > Makefile
- mv lib/Makefile lib/Makefile.orig
- sed -e 's/SHELL/SHELLZZ/g' < lib/Makefile.orig > lib/Makefile
- mv doc/Makefile doc/Makefile.orig
- sed -e 's/SHELL/SHELLZZ/g' < doc/Makefile.orig > doc/Makefile
- mv examples/Makefile examples/Makefile.orig
- sed -e 's/SHELL/SHELLZZ/g' < examples/Makefile.orig > examples/Makefile
- mv tests/Makefile tests/Makefile.orig
- sed -e 's/SHELL/SHELLZZ/g' < tests/Makefile.orig > tests/Makefile
- mv xmlwf/Makefile xmlwf/Makefile.orig
- sed -e 's/SHELL/SHELLZZ/g' < xmlwf/Makefile.orig > xmlwf/Makefile
- echo "make"
- make
- echo "make install"
- make install
- cd ..
- echo "unbound"
- cd unbound
- echo "./configure --enable-debug --enable-static-exe --disable-flto \"--with-ssl=$prepath/openssl\" --with-libexpat=\"$prepath/expat\" --disable-shared"
- ./configure --enable-debug --enable-static-exe --disable-flto "--with-ssl=$prepath/openssl" --with-libexpat="$prepath/expat" --disable-shared
- make
- # specific test output
- #make testbound.exe; ./testbound.exe -s
- #make testbound; ./testbound.exe -p testdata/acl.rpl -o -vvvv
- make test
- - name: test_android
- if: ${{ matrix.test_android == 'yes' }}
- env:
- AUTOTOOLS_HOST: ${{ matrix.AUTOTOOLS_HOST }}
- OPENSSL_HOST: ${{ matrix.OPENSSL_HOST }}
- ANDROID_API: ${{ matrix.ANDROID_API }}
- ANDROID_CPU: ${{ matrix.ANDROID_CPU }}
- run: |
- #(already installed) ./contrib/android/install_tools.sh
- export ANDROID_PREFIX="$HOME/android$ANDROID_API-$ANDROID_CPU"
- echo ANDROID_PREFIX=${ANDROID_PREFIX}
- export ANDROID_SDK_ROOT="$HOME/android-sdk"
- echo ANDROID_SDK_ROOT=${ANDROID_SDK_ROOT}
- export ANDROID_NDK_ROOT="$HOME/android-ndk"
- echo ANDROID_NDK_ROOT=${ANDROID_NDK_ROOT}
- export AUTOTOOLS_BUILD="$(./config.guess)"
- echo AUTOTOOLS_BUILD=${AUTOTOOLS_BUILD}
- export PKG_CONFIG_PATH="$ANDROID_PREFIX/lib/pkgconfig"
- echo PKG_CONFIG_PATH=${PKG_CONFIG_PATH}
- export CONFIG_OPTS="--build=$AUTOTOOLS_BUILD --host=$AUTOTOOLS_HOST --prefix=$ANDROID_PREFIX --with-ssl=$ANDROID_PREFIX --disable-gost --with-libexpat=$ANDROID_PREFIX"
- echo CONFIG_OPTS=${CONFIG_OPTS}
- echo "::group::install_ndk"
- echo "./contrib/android/install_ndk.sh"
- ./contrib/android/install_ndk.sh
- echo "::endgroup::"
- echo "::group::setenv_android.sh"
- echo "./contrib/android/setenv_android.sh"
- source ./contrib/android/setenv_android.sh
- echo "::endgroup::"
- echo "::group::install_openssl"
- echo "./contrib/android/install_openssl.sh"
- ./contrib/android/install_openssl.sh
- echo "::endgroup::"
- echo "::group::install_expat"
- echo "./contrib/android/install_expat.sh"
- ./contrib/android/install_expat.sh
- echo "::endgroup::"
- echo "::group::configure"
- echo "./configure ${CONFIG_OPTS}"
- ./configure ${CONFIG_OPTS}
- echo "::endgroup::"
- echo "::group::make"
- # make is here to preserve environment variables
- make
- echo "::endgroup::"
- echo "::group::make install"
- make install
- echo "::endgroup::"
- - name: test ios
- if: ${{ matrix.test_ios == 'yes' }}
- env:
- AUTOTOOLS_HOST: ${{ matrix.AUTOTOOLS_HOST }}
- OPENSSL_HOST: ${{ matrix.OPENSSL_HOST }}
- IOS_SDK: ${{ matrix.IOS_SDK }}
- IOS_CPU: ${{ matrix.IOS_CPU }}
- run: |
- #(already installed) ./contrib/ios/install_tools.sh
- export AUTOTOOLS_BUILD="$(./config.guess)"
- echo AUTOTOOLS_BUILD=${AUTOTOOLS_BUILD}
- export IOS_PREFIX="$HOME/$IOS_SDK-$IOS_CPU"
- echo IOS_PREFIX=${IOS_PREFIX}
- export PKG_CONFIG_PATH="$IOS_PREFIX/lib/pkgconfig"
- echo PKG_CONFIG_PATH=${PKG_CONFIG_PATH}
- export CONFIG_OPTS="--build=$AUTOTOOLS_BUILD --host=$AUTOTOOLS_HOST --prefix=$IOS_PREFIX --with-ssl=$IOS_PREFIX --disable-gost --with-libexpat=$IOS_PREFIX"
- echo CONFIG_OPTS=${CONFIG_OPTS}
- echo "::group::setenv_ios.sh"
- echo "./contrib/ios/setenv_ios.sh"
- source ./contrib/ios/setenv_ios.sh
- echo "::endgroup::"
- echo "::group::install_openssl"
- echo "./contrib/ios/install_openssl.sh"
- ./contrib/ios/install_openssl.sh
- echo "::endgroup::"
- echo "::group::install_expat"
- echo "./contrib/ios/install_expat.sh"
- ./contrib/ios/install_expat.sh
- echo "::endgroup::"
- echo "::group::configure"
- echo "./configure ${CONFIG_OPTS}"
- ./configure ${CONFIG_OPTS}
- echo "::endgroup::"
- echo "::group::make"
- # make is here to preserve environment variables
- make
- echo "::endgroup::"
- echo "::group::make install"
- make install
- echo "::endgroup::"
- - name: install libevent
- if: ${{ matrix.install_libevent == 'yes' }}
- run: sudo apt-get install libevent-dev
- - name: install expat
- if: ${{ matrix.install_expat == 'yes' }}
- run: brew install expat
- - name: configure
- if: ${{ matrix.config != 'no' }}
- run: ./configure ${{ matrix.config }}
- - name: make
- if: ${{ matrix.make != 'no' }}
- run: make
- - name: make test
- if: ${{ matrix.make_test == 'yes' }}
- run: make test
- - name: clang-analysis
- if: ${{ matrix.clang_analysis == 'yes' }}
- run: (cd testdata/clang-analysis.tdir; bash clang-analysis.test)
diff --git a/contrib/unbound/.github/workflows/ci.yml b/contrib/unbound/.github/workflows/ci.yml
deleted file mode 100644
index 73d68fbf35c9..000000000000
--- a/contrib/unbound/.github/workflows/ci.yml
+++ /dev/null
@@ -1,21 +0,0 @@
-name: ci
-
-on:
- push:
- branches: [ master ]
- pull_request:
- branches: [ master ]
-
-jobs:
- build:
-
- runs-on: ubuntu-latest
-
- steps:
- - uses: actions/checkout@v2
- - name: configure
- run: ./configure --enable-debug
- - name: make
- run: make
- - name: make test
- run: make test
diff --git a/contrib/unbound/.travis.yml b/contrib/unbound/.travis.yml
deleted file mode 100644
index 1f514b5d08d4..000000000000
--- a/contrib/unbound/.travis.yml
+++ /dev/null
@@ -1,380 +0,0 @@
-language: c
-
-git:
- depth: 5
-
-addons:
- apt:
- packages:
- - libssl-dev
- - libevent-dev
- - libexpat-dev
- - clang
- homebrew:
- packages:
- - openssl
- - libevent
- - expat
- # homebrew update takes 20min or hangs, so disable update
- #update: true
-
-jobs:
- include:
- - os: linux
- name: GCC on Linux, Amd64
- compiler: gcc
- arch: amd64
- env:
- - CONFIG_OPTS="--enable-debug --disable-flto"
- - os: linux
- name: Clang on Linux, Amd64, clang-analysis
- compiler: clang
- arch: amd64
- env:
- - CONFIG_OPTS="--enable-debug --disable-flto"
- - TEST_ANALYZER=yes
- - os: osx
- osx_image: xcode12.2
- name: Clang on OS X, Amd64, clang-analysis
- compiler: clang
- arch: amd64
- env:
- - TEST_OSX=yes
- - CONFIG_OPTS="--enable-debug --disable-flto --with-ssl=/usr/local/opt/openssl --with-libexpat=/usr/local/opt/expat"
- - TEST_ANALYZER=yes
- - HOMEBREW_NO_AUTO_UPDATE=1
- - os: linux
- name: Libevent, GCC on Linux, Amd64
- compiler: gcc
- arch: amd64
- env:
- - TEST_LIBEVENT=yes
- - CONFIG_OPTS="--with-libevent"
- - os: linux
- name: Libevent, Clang on Linux, Amd64
- compiler: clang
- arch: amd64
- env:
- - TEST_LIBEVENT=yes
- - CONFIG_OPTS="--with-libevent"
- - os: osx
- osx_image: xcode12.2
- name: Libevent, Clang on OS X, Amd64
- compiler: clang
- arch: amd64
- env:
- - TEST_OSX=yes
- - TEST_LIBEVENT=yes
- - CONFIG_OPTS="--disable-flto --with-ssl=/usr/local/opt/openssl --with-libevent=/usr/local/opt/libevent --with-libexpat=/usr/local/opt/expat"
- - HOMEBREW_NO_AUTO_UPDATE=1
- - os: linux
- name: UBsan, GCC on Linux, Amd64
- compiler: gcc
- arch: amd64
- dist: bionic
- env:
- - TEST_UBSAN=yes
- - os: linux
- name: UBsan, Clang on Linux, Amd64
- compiler: clang
- arch: amd64
- dist: bionic
- env:
- - TEST_UBSAN=yes
- - os: linux
- name: Asan, GCC on Linux, Amd64
- compiler: gcc
- arch: amd64
- dist: bionic
- env:
- - TEST_ASAN=yes
- - os: linux
- name: Asan, Clang on Linux, Amd64
- compiler: clang
- arch: amd64
- dist: bionic
- env:
- - TEST_ASAN=yes
- - os: linux
- name: GCC on Linux, Aarch64
- compiler: gcc
- arch: arm64
- dist: bionic
- env:
- - CONFIG_OPTS="--enable-debug --disable-flto"
- - os: linux
- name: Clang on Linux, Aarch64
- compiler: clang
- arch: arm64
- dist: bionic
- env:
- - CONFIG_OPTS="--enable-debug --disable-flto"
- - os: linux
- name: GCC on Linux, PowerPC64
- compiler: gcc
- arch: ppc64le
- dist: bionic
- env:
- - CONFIG_OPTS="--enable-debug --disable-flto"
- - os: linux
- name: Clang on Linux, PowerPC64
- compiler: clang
- arch: ppc64le
- dist: bionic
- env:
- - CONFIG_OPTS="--enable-debug --disable-flto"
- - os: linux
- name: GCC on Linux, s390x
- compiler: gcc
- arch: s390x
- dist: bionic
- env:
- - CONFIG_OPTS="--enable-debug --disable-flto"
- - os: linux
- name: Clang on Linux, s390x
- compiler: clang
- arch: s390x
- dist: bionic
- env:
- - CONFIG_OPTS="--enable-debug --disable-flto"
- - os: osx
- osx_image: xcode12.2
- name: Apple iPhone on iOS, armv7
- compiler: clang
- env:
- - TEST_IOS=yes
- - AUTOTOOLS_HOST=armv7-apple-ios
- - OPENSSL_HOST=ios-cross
- - IOS_SDK=iPhoneOS
- - IOS_CPU=armv7s
- - IOS_PREFIX="$HOME/$IOS_SDK-$IOS_CPU"
- - HOMEBREW_NO_AUTO_UPDATE=1
- - os: osx
- osx_image: xcode12.2
- name: Apple iPhone on iOS, arm64
- compiler: clang
- env:
- - TEST_IOS=yes
- - AUTOTOOLS_HOST=aarch64-apple-ios
- - OPENSSL_HOST=ios64-cross
- - IOS_SDK=iPhoneOS
- - IOS_CPU=arm64
- - IOS_PREFIX="$HOME/$IOS_SDK-$IOS_CPU"
- - HOMEBREW_NO_AUTO_UPDATE=1
- - os: osx
- osx_image: xcode12.2
- name: Apple TV on iOS, arm64
- compiler: clang
- env:
- - TEST_IOS=yes
- - AUTOTOOLS_HOST=aarch64-apple-ios
- - OPENSSL_HOST=ios64-cross
- - IOS_SDK=AppleTVOS
- - IOS_CPU=arm64
- - IOS_PREFIX="$HOME/$IOS_SDK-$IOS_CPU"
- - HOMEBREW_NO_AUTO_UPDATE=1
- - os: osx
- osx_image: xcode12.2
- name: Apple Watch on iOS, armv7
- compiler: clang
- env:
- - TEST_IOS=yes
- - AUTOTOOLS_HOST=armv7-apple-ios
- - OPENSSL_HOST=ios-cross
- - IOS_SDK=WatchOS
- - IOS_CPU=armv7k
- - IOS_PREFIX="$HOME/$IOS_SDK-$IOS_CPU"
- - HOMEBREW_NO_AUTO_UPDATE=1
- - os: osx
- osx_image: xcode12.2
- name: iPhoneSimulator on OS X, i386
- env:
- - TEST_IOS=yes
- - AUTOTOOLS_HOST=i386-apple-ios
- - OPENSSL_HOST=iphoneos-cross
- - IOS_CPU=i386
- - IOS_SDK=iPhoneSimulator
- - IOS_PREFIX="$HOME/$IOS_SDK-$IOS_CPU"
- - HOMEBREW_NO_AUTO_UPDATE=1
- - os: osx
- osx_image: xcode12.2
- name: iPhoneSimulator on OS X, x86_64
- env:
- - TEST_IOS=yes
- - AUTOTOOLS_HOST=x86_64-apple-ios
- - OPENSSL_HOST=iphoneos-cross
- - IOS_CPU=x86_64
- - IOS_SDK=iPhoneSimulator
- - IOS_PREFIX="$HOME/$IOS_SDK-$IOS_CPU"
- - HOMEBREW_NO_AUTO_UPDATE=1
- - os: osx
- osx_image: xcode12.2
- name: AppleTVSimulator on OS X, x86_64
- env:
- - TEST_IOS=yes
- - AUTOTOOLS_HOST=x86_64-apple-ios
- - OPENSSL_HOST=iphoneos-cross
- - IOS_CPU=x86_64
- - IOS_SDK=AppleTVSimulator
- - IOS_PREFIX="$HOME/$IOS_SDK-$IOS_CPU"
- - HOMEBREW_NO_AUTO_UPDATE=1
- - os: osx
- osx_image: xcode12.2
- name: WatchSimulator on OS X, i386
- env:
- - TEST_IOS=yes
- - AUTOTOOLS_HOST=i386-apple-ios
- - OPENSSL_HOST=iphoneos-cross
- - IOS_CPU=i386
- - IOS_SDK=WatchSimulator
- - IOS_PREFIX="$HOME/$IOS_SDK-$IOS_CPU"
- - HOMEBREW_NO_AUTO_UPDATE=1
- - os: linux
- name: Android armv7a, Linux, Amd64
- compiler: clang
- arch: amd64
- dist: bionic
- env:
- - TEST_ANDROID=yes
- - AUTOTOOLS_HOST=armv7a-linux-androideabi
- - OPENSSL_HOST=android-arm
- - ANDROID_CPU=armv7a
- - ANDROID_API=23
- - ANDROID_PREFIX="$HOME/android$ANDROID_API-$ANDROID_CPU"
- - ANDROID_SDK_ROOT="$HOME/android-sdk"
- - ANDROID_NDK_ROOT="$HOME/android-ndk"
- - os: linux
- name: Android aarch64, Linux, Amd64
- compiler: clang
- arch: amd64
- dist: bionic
- env:
- - TEST_ANDROID=yes
- - AUTOTOOLS_HOST=aarch64-linux-android
- - OPENSSL_HOST=android-arm64
- - ANDROID_CPU=aarch64
- - ANDROID_API=23
- - ANDROID_PREFIX="$HOME/android$ANDROID_API-$ANDROID_CPU"
- - ANDROID_SDK_ROOT="$HOME/android-sdk"
- - ANDROID_NDK_ROOT="$HOME/android-ndk"
- - os: linux
- name: Android x86, Linux, Amd64
- compiler: clang
- arch: amd64
- dist: bionic
- env:
- - TEST_ANDROID=yes
- - AUTOTOOLS_HOST=i686-linux-android
- - OPENSSL_HOST=android-x86
- - ANDROID_CPU=x86
- - ANDROID_API=23
- - ANDROID_PREFIX="$HOME/android$ANDROID_API-$ANDROID_CPU"
- - ANDROID_SDK_ROOT="$HOME/android-sdk"
- - ANDROID_NDK_ROOT="$HOME/android-ndk"
- - os: linux
- name: Android x86_64, Linux, Amd64
- compiler: clang
- arch: amd64
- dist: bionic
- env:
- - TEST_ANDROID=yes
- - AUTOTOOLS_HOST=x86_64-linux-android
- - OPENSSL_HOST=android-x86_64
- - ANDROID_CPU=x86_64
- - ANDROID_API=23
- - ANDROID_PREFIX="$HOME/android$ANDROID_API-$ANDROID_CPU"
- - ANDROID_SDK_ROOT="$HOME/android-sdk"
- - ANDROID_NDK_ROOT="$HOME/android-ndk"
-
- allow_failures:
- - os: osx
- name: Apple iPhone on iOS, armv7
- - os: osx
- name: Apple iPhone on iOS, arm64
- - os: osx
- name: Apple TV on iOS, arm64
- - os: osx
- name: Apple Watch on iOS, armv7
- - os: osx
- name: iPhoneSimulator on OS X, i386
- - os: osx
- name: iPhoneSimulator on OS X, x86_64
- - os: osx
- name: AppleTVSimulator on OS X, x86_64
- - os: osx
- name: WatchSimulator on OS X, i386
- - os: linux
- name: Android armv7a, Linux, Amd64
- - os: linux
- name: Android aarch64, Linux, Amd64
- - os: linux
- name: Android x86, Linux, Amd64
- - os: linux
- name: Android x86_64, Linux, Amd64
-
-before_script:
- - |
- if [ "$TEST_ANDROID" = "yes" ]; then
- ./contrib/android/install_tools.sh
- elif [ "$TEST_IOS" = "yes" ]; then
- ./contrib/ios/install_tools.sh
- fi
-
-# The Travis docs say to avoid calling exit in the script. It leads to
-# some code duplication to avoid failures in cross-compiles. Also see
-# https://docs.travis-ci.com/user/job-lifecycle/ in the Travis docs.
-script:
- - |
- export MAKE_TEST="yes"
- if [ "$TEST_UBSAN" = "yes" ]; then
- export CFLAGS="-DNDEBUG -g2 -O3 -fsanitize=undefined -fno-sanitize-recover=all"
- elif [ "$TEST_ASAN" = "yes" ]; then
- export CFLAGS="-DNDEBUG -g2 -O3 -fsanitize=address"
- fi
- - |
- if [ "$TEST_IOS" = "yes" ]; then
- export AUTOTOOLS_BUILD="$(./config.guess)"
- export PKG_CONFIG_PATH="$IOS_PREFIX/lib/pkgconfig"
- source ./contrib/ios/setenv_ios.sh
- ./contrib/ios/install_openssl.sh
- ./contrib/ios/install_expat.sh
- export CONFIG_OPTS="\
- --build=$AUTOTOOLS_BUILD --host=$AUTOTOOLS_HOST \
- --prefix=$IOS_PREFIX \
- --with-ssl=$IOS_PREFIX --disable-gost \
- --with-libexpat=$IOS_PREFIX "
- echo CONFIG_OPTS ${CONFIG_OPTS}
- export MAKE_TEST=no
- export TEST_INSTALL=yes
- fi
- - |
- if [ "$TEST_ANDROID" = "yes" ]; then
- export AUTOTOOLS_BUILD="$(./config.guess)"
- export PKG_CONFIG_PATH="$ANDROID_PREFIX/lib/pkgconfig"
- ./contrib/android/install_ndk.sh
- source ./contrib/android/setenv_android.sh
- ./contrib/android/install_openssl.sh
- ./contrib/android/install_expat.sh
- export CONFIG_OPTS="\
- --build=$AUTOTOOLS_BUILD --host=$AUTOTOOLS_HOST \
- --prefix=$ANDROID_PREFIX \
- --with-ssl=$ANDROID_PREFIX --disable-gost \
- --with-libexpat=$ANDROID_PREFIX "
- echo CONFIG_OPTS ${CONFIG_OPTS}
- export MAKE_TEST=no
- export TEST_INSTALL=yes
- fi
- - ./configure ${CONFIG_OPTS}
- - make -j 2
- - |
- if [ "$MAKE_TEST" = "yes" ]; then
- make test
- fi
- - |
- if [ "$TEST_INSTALL" = "yes" ]; then
- make install
- fi
- - |
- if [ "$TEST_ANALYZER" = "yes" ]; then
- (cd testdata/clang-analysis.tdir; bash clang-analysis.test)
- fi
diff --git a/contrib/unbound/Makefile.in b/contrib/unbound/Makefile.in
index ff5dc8fae856..55125a441977 100644
--- a/contrib/unbound/Makefile.in
+++ b/contrib/unbound/Makefile.in
@@ -61,6 +61,7 @@ PYTHON_CPPFLAGS=-I. @PYTHON_CPPFLAGS@
CFLAGS=-DSRCDIR=$(srcdir) @CFLAGS@
LDFLAGS=@LDFLAGS@
LIBS=@LIBS@
+PYTHON_LIBS=@PYTHON_LIBS@
LIBOBJS=@LIBOBJS@
# filter out ctime_r from compat obj.
LIBOBJ_WITHOUT_CTIME=@LIBOBJ_WITHOUT_CTIME@
@@ -85,6 +86,8 @@ LINTFLAGS+=@NETBSD_LINTFLAGS@
LINTFLAGS+="-Dsigset_t=long"
# FreeBSD
LINTFLAGS+="-D__uint16_t=uint16_t" "-DEVP_PKEY_ASN1_METHOD=int" "-D_RuneLocale=int" "-D__va_list=va_list" "-D__uint32_t=uint32_t" "-D_Alignof(x)=x" "-D__aligned(x)=" "-D__requires_exclusive(x)=" "-D__requires_unlocked(x)=" "-D__locks_exclusive(x)=" "-D__trylocks_exclusive(x)=" "-D__unlocks(x)=" "-D__locks_shared(x)=" "-D__trylocks_shared(x)="
+# GCC Docker
+LINTFLAGS+=@GCC_DOCKER_LINTFLAGS@
INSTALL=$(SHELL) $(srcdir)/install-sh
@@ -476,7 +479,7 @@ libunbound/python/libunbound_wrap.c: $(srcdir)/libunbound/python/libunbound.i un
# Pyunbound python unbound wrapper
_unbound.la: libunbound_wrap.lo libunbound.la
- $(LIBTOOL) --tag=CC --mode=link $(CC) $(RUNTIME_PATH) $(CPPFLAGS) $(CFLAGS) $(LDFLAGS) -module -avoid-version -no-undefined -shared -o $@ libunbound_wrap.lo -rpath $(PYTHON_SITE_PKG) -L. -L.libs libunbound.la $(LIBS)
+ $(LIBTOOL) --tag=CC --mode=link $(CC) $(RUNTIME_PATH) $(CPPFLAGS) $(CFLAGS) $(LDFLAGS) -module -avoid-version -no-undefined -shared -o $@ libunbound_wrap.lo -rpath $(PYTHON_SITE_PKG) -L. -L.libs libunbound.la $(PYTHON_LIBS)
util/config_file.c: util/configparser.h
util/configlexer.c: $(srcdir)/util/configlexer.lex util/configparser.h
diff --git a/contrib/unbound/README-Travis.md b/contrib/unbound/README-Travis.md
index 3ce22cc20f59..ca64456124af 100644
--- a/contrib/unbound/README-Travis.md
+++ b/contrib/unbound/README-Travis.md
@@ -241,7 +241,7 @@ If you are working from a developer machine you probably already have the necess
The fourth step builds OpenSSL and Expat. OpenSSL and Expat are built for iOS using the scripts `contrib/ios/install_openssl.sh` and `contrib/ios/install_expat.sh`. The scripts download, configure and install the latest release version of the libraries. The libraries are configured with `--prefix="$IOS_PREFIX"` so the headers are placed in `$IOS_PREFIX/include` directory, and the libraries are placed in the `$IOS_PREFIX/lib` directory.
-`IOS_PREFIX` is the value `$HOME/$IOS_SDK-$IOS_CPU`. The scheme handles both iOS SDKs and cpu architectures so the pair recieves a unique installation directory. The libraries will be installed in `$HOME/iPhoneOS-armv7s`, `$HOME/iPhoneOS-arm64`, `$HOME/iPhoneSimulator-i386`, etc. For Autotools projects, the appropriate `PKG_CONFIG_PATH` is exported.
+`IOS_PREFIX` is the value `$HOME/$IOS_SDK-$IOS_CPU`. The scheme handles both iOS SDKs and cpu architectures so the pair receives a unique installation directory. The libraries will be installed in `$HOME/iPhoneOS-armv7s`, `$HOME/iPhoneOS-arm64`, `$HOME/iPhoneSimulator-i386`, etc. For Autotools projects, the appropriate `PKG_CONFIG_PATH` is exported.
`PKG_CONFIG_PATH` is an important variable. It is the userland equivalent to sysroot, and allows Autotools to find non-system headers and libraries for an architecture. Typical `PKG_CONFIG_PATH` are `$HOME/iPhoneOS-armv7s/lib/pkgconfig` and `$HOME/iPhoneOS-arm64/lib/pkgconfig`.
diff --git a/contrib/unbound/acx_nlnetlabs.m4 b/contrib/unbound/acx_nlnetlabs.m4
index 39e92d875331..1574f97bfe02 100644
--- a/contrib/unbound/acx_nlnetlabs.m4
+++ b/contrib/unbound/acx_nlnetlabs.m4
@@ -2,7 +2,10 @@
# Copyright 2009, Wouter Wijngaards, NLnet Labs.
# BSD licensed.
#
-# Version 41
+# Version 43
+# 2021-08-17 fix sed script in ssldir split handling.
+# 2021-08-17 fix for openssl to detect split version, with ssldir_include
+# and ssldir_lib output directories.
# 2021-07-30 fix for openssl use of lib64 directory.
# 2021-06-14 fix nonblocking test to use host instead of target for mingw test.
# 2021-05-17 fix nonblocking socket test from grep on mingw32 to mingw for
@@ -647,6 +650,30 @@ AC_DEFUN([ACX_SSL_CHECKS], [
withval=$1
if test x_$withval != x_no; then
AC_MSG_CHECKING(for SSL)
+ if test -n "$withval"; then
+ dnl look for openssl install with different version, eg.
+ dnl in /usr/include/openssl11/openssl/ssl.h
+ dnl and /usr/lib64/openssl11/libssl.so
+ dnl with the --with-ssl=/usr/include/openssl11
+ if test ! -f "$withval/include/openssl/ssl.h" -a -f "$withval/openssl/ssl.h"; then
+ ssldir="$withval"
+ found_ssl="yes"
+ withval=""
+ ssldir_include="$ssldir"
+ dnl find the libdir
+ ssldir_lib=`echo $ssldir | sed -e 's/include/lib/'`
+ if test -f "$ssldir_lib/libssl.a" -o -f "$ssldir_lib/libssl.so"; then
+ : # found here
+ else
+ ssldir_lib=`echo $ssldir | sed -e 's/include/lib64/'`
+ if test -f "$ssldir_lib/libssl.a" -o -f "$ssldir_lib/libssl.so"; then
+ : # found here
+ else
+ AC_MSG_ERROR([Could not find openssl lib file, $ssldir_lib/libssl.[so,a], pass like "/usr/local" or "/usr/include/openssl11"])
+ fi
+ fi
+ fi
+ fi
if test x_$withval = x_ -o x_$withval = x_yes; then
withval="/usr/local/ssl /usr/lib/ssl /usr/ssl /usr/pkg /usr/local /opt/local /usr/sfw /usr"
fi
@@ -654,12 +681,12 @@ AC_DEFUN([ACX_SSL_CHECKS], [
ssldir="$dir"
if test -f "$dir/include/openssl/ssl.h"; then
found_ssl="yes"
- AC_DEFINE_UNQUOTED([HAVE_SSL], [], [Define if you have the SSL libraries installed.])
- dnl assume /usr/include is already in the include-path.
- if test "$ssldir" != "/usr"; then
- CPPFLAGS="$CPPFLAGS -I$ssldir/include"
- LIBSSL_CPPFLAGS="$LIBSSL_CPPFLAGS -I$ssldir/include"
- fi
+ ssldir_include="$ssldir/include"
+ if test ! -d "$ssldir/lib" -a -d "$ssldir/lib64"; then
+ ssldir_lib="$ssldir/lib64"
+ else
+ ssldir_lib="$ssldir/lib"
+ fi
break;
fi
done
@@ -667,19 +694,16 @@ AC_DEFUN([ACX_SSL_CHECKS], [
AC_MSG_ERROR(Cannot find the SSL libraries in $withval)
else
AC_MSG_RESULT(found in $ssldir)
+ AC_DEFINE_UNQUOTED([HAVE_SSL], [], [Define if you have the SSL libraries installed.])
HAVE_SSL=yes
- dnl assume /usr is already in the lib and dynlib paths.
- if test "$ssldir" != "/usr" -a "$ssldir" != ""; then
- if test ! -d "$ssldir/lib" -a -d "$ssldir/lib64"; then
- LDFLAGS="$LDFLAGS -L$ssldir/lib64"
- LIBSSL_LDFLAGS="$LIBSSL_LDFLAGS -L$ssldir/lib64"
- ACX_RUNTIME_PATH_ADD([$ssldir/lib64])
- else
- LDFLAGS="$LDFLAGS -L$ssldir/lib"
- LIBSSL_LDFLAGS="$LIBSSL_LDFLAGS -L$ssldir/lib"
- ACX_RUNTIME_PATH_ADD([$ssldir/lib])
- fi
- fi
+ dnl assume /usr is already in the include, lib and dynlib paths.
+ if test "$ssldir" != "/usr"; then
+ CPPFLAGS="$CPPFLAGS -I$ssldir_include"
+ LIBSSL_CPPFLAGS="$LIBSSL_CPPFLAGS -I$ssldir_include"
+ LDFLAGS="$LDFLAGS -L$ssldir_lib"
+ LIBSSL_LDFLAGS="$LIBSSL_LDFLAGS -L$ssldir_lib"
+ ACX_RUNTIME_PATH_ADD([$ssldir_lib])
+ fi
AC_MSG_CHECKING([for EVP_sha256 in -lcrypto])
LIBS="$LIBS -lcrypto"
@@ -758,7 +782,7 @@ dnl
AC_DEFUN([ACX_WITH_SSL],
[
AC_ARG_WITH(ssl, AS_HELP_STRING([--with-ssl=pathname],[enable SSL (will check /usr/local/ssl
- /usr/lib/ssl /usr/ssl /usr/pkg /usr/local /opt/local /usr/sfw /usr)]),[
+ /usr/lib/ssl /usr/ssl /usr/pkg /usr/local /opt/local /usr/sfw /usr or specify like /usr/include/openssl11)]),[
],[
withval="yes"
])
@@ -776,7 +800,7 @@ dnl
AC_DEFUN([ACX_WITH_SSL_OPTIONAL],
[
AC_ARG_WITH(ssl, AS_HELP_STRING([--with-ssl=pathname],[enable SSL (will check /usr/local/ssl
- /usr/lib/ssl /usr/ssl /usr/pkg /usr/local /opt/local /usr/sfw /usr)]),[
+ /usr/lib/ssl /usr/ssl /usr/pkg /usr/local /opt/local /usr/sfw /usr or specify like /usr/include/openssl11)]),[
],[
withval="yes"
])
diff --git a/contrib/unbound/cachedb/cachedb.c b/contrib/unbound/cachedb/cachedb.c
index af4ffe5f28b5..725bc6ce8b38 100644
--- a/contrib/unbound/cachedb/cachedb.c
+++ b/contrib/unbound/cachedb/cachedb.c
@@ -519,7 +519,7 @@ parse_data(struct module_qstate* qstate, struct sldns_buffer* buf)
sldns_buffer_set_limit(buf, lim);
return 0;
}
- if(parse_extract_edns(prs, &edns, qstate->env->scratch) !=
+ if(parse_extract_edns_from_response_msg(prs, &edns, qstate->env->scratch) !=
LDNS_RCODE_NOERROR) {
sldns_buffer_set_limit(buf, lim);
return 0;
diff --git a/contrib/unbound/config.h.in b/contrib/unbound/config.h.in
index ea6afa4802ee..e8a26735d2d3 100644
--- a/contrib/unbound/config.h.in
+++ b/contrib/unbound/config.h.in
@@ -72,6 +72,9 @@
/* If we have be64toh */
#undef HAVE_BE64TOH
+/* Define to 1 if you have the `BIO_set_callback_ex' function. */
+#undef HAVE_BIO_SET_CALLBACK_EX
+
/* Define to 1 if you have the <bsd/stdlib.h> header file. */
#undef HAVE_BSD_STDLIB_H
@@ -315,6 +318,9 @@
/* Define to 1 if you have the <ifaddrs.h> header file. */
#undef HAVE_IFADDRS_H
+/* Define to 1 if you have the `if_nametoindex' function. */
+#undef HAVE_IF_NAMETOINDEX
+
/* Define to 1 if you have the `inet_aton' function. */
#undef HAVE_INET_ATON
diff --git a/contrib/unbound/config.sub b/contrib/unbound/config.sub
index d80c5d759e48..d74fb6deac94 100755
--- a/contrib/unbound/config.sub
+++ b/contrib/unbound/config.sub
@@ -4,7 +4,7 @@
# shellcheck disable=SC2006,SC2268 # see below for rationale
-timestamp='2021-07-03'
+timestamp='2021-08-14'
# 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
@@ -121,9 +121,11 @@ esac
# Split fields of configuration type
# shellcheck disable=SC2162
+saved_IFS=$IFS
IFS="-" read field1 field2 field3 field4 <<EOF
$1
EOF
+IFS=$saved_IFS
# Separate into logical components for further validation
case $1 in
@@ -172,6 +174,10 @@ case $1 in
basic_machine=$field1
basic_os=$field2
;;
+ zephyr*)
+ basic_machine=$field1-unknown
+ basic_os=$field2
+ ;;
# Manufacturers
dec* | mips* | sequent* | encore* | pc533* | sgi* | sony* \
| att* | 7300* | 3300* | delta* | motorola* | sun[234]* \
@@ -931,9 +937,11 @@ case $basic_machine in
*-*)
# shellcheck disable=SC2162
+ saved_IFS=$IFS
IFS="-" read cpu vendor <<EOF
$basic_machine
EOF
+ IFS=$saved_IFS
;;
# We use `pc' rather than `unknown'
# because (1) that's what they normally are, and
@@ -1313,9 +1321,11 @@ case $basic_os in
;;
*-*)
# shellcheck disable=SC2162
+ saved_IFS=$IFS
IFS="-" read kernel os <<EOF
$basic_os
EOF
+ IFS=$saved_IFS
;;
# Default OS when just kernel was specified
nto*)
@@ -1697,7 +1707,7 @@ fi
# Now, validate our (potentially fixed-up) OS.
case $os in
# Sometimes we do "kernel-libc", so those need to count as OSes.
- musl* | newlib* | uclibc*)
+ musl* | newlib* | relibc* | uclibc*)
;;
# Likewise for "kernel-abi"
eabi* | gnueabi*)
@@ -1738,7 +1748,7 @@ case $os in
| skyos* | haiku* | rdos* | toppers* | drops* | es* \
| onefs* | tirtos* | phoenix* | fuchsia* | redox* | bme* \
| midnightbsd* | amdhsa* | unleashed* | emscripten* | wasi* \
- | nsk* | powerunix* | genode* | zvmoe* | qnx* | emx*)
+ | nsk* | powerunix* | genode* | zvmoe* | qnx* | emx* | zephyr*)
;;
# This one is extra strict with allowed versions
sco3.2v2 | sco3.2v[4-9]* | sco5v6*)
@@ -1755,11 +1765,12 @@ esac
# As a final step for OS-related things, validate the OS-kernel combination
# (given a valid OS), if there is a kernel.
case $kernel-$os in
- linux-gnu* | linux-dietlibc* | linux-android* | linux-newlib* | linux-musl* | linux-uclibc* )
+ linux-gnu* | linux-dietlibc* | linux-android* | linux-newlib* \
+ | linux-musl* | linux-relibc* | linux-uclibc* )
;;
uclinux-uclibc* )
;;
- -dietlibc* | -newlib* | -musl* | -uclibc* )
+ -dietlibc* | -newlib* | -musl* | -relibc* | -uclibc* )
# These are just libc implementations, not actual OSes, and thus
# require a kernel.
echo "Invalid configuration \`$1': libc \`$os' needs explicit kernel." 1>&2
diff --git a/contrib/unbound/configure b/contrib/unbound/configure
index 346fd5e5b076..df25819eabbf 100755
--- a/contrib/unbound/configure
+++ b/contrib/unbound/configure
@@ -1,6 +1,6 @@
#! /bin/sh
# Guess values for system-dependent variables and create Makefiles.
-# Generated by GNU Autoconf 2.69 for unbound 1.13.2.
+# Generated by GNU Autoconf 2.69 for unbound 1.14.0rc1.
#
# Report bugs to <unbound-bugs@nlnetlabs.nl or https://github.com/NLnetLabs/unbound/issues>.
#
@@ -591,8 +591,8 @@ MAKEFLAGS=
# Identity of this package.
PACKAGE_NAME='unbound'
PACKAGE_TARNAME='unbound'
-PACKAGE_VERSION='1.13.2'
-PACKAGE_STRING='unbound 1.13.2'
+PACKAGE_VERSION='1.14.0rc1'
+PACKAGE_STRING='unbound 1.14.0rc1'
PACKAGE_BUGREPORT='unbound-bugs@nlnetlabs.nl or https://github.com/NLnetLabs/unbound/issues'
PACKAGE_URL=''
@@ -682,6 +682,7 @@ SSLLIB
HAVE_SSL
PC_CRYPTO_DEPENDENCY
CONFIG_DATE
+GCC_DOCKER_LINTFLAGS
NETBSD_LINTFLAGS
PYUNBOUND_UNINSTALL
PYUNBOUND_INSTALL
@@ -697,6 +698,7 @@ swig
SWIG_LIB
SWIG
PC_PY_DEPENDENCY
+PYTHON_LIBS
PY_MAJOR_VERSION
PYTHON_SITE_PKG
PYTHON_LDFLAGS
@@ -1464,7 +1466,7 @@ if test "$ac_init_help" = "long"; then
# Omit some internal or obsolete options to make the list less imposing.
# This message is too long to be a string in the A/UX 3.1 sh.
cat <<_ACEOF
-\`configure' configures unbound 1.13.2 to adapt to many kinds of systems.
+\`configure' configures unbound 1.14.0rc1 to adapt to many kinds of systems.
Usage: $0 [OPTION]... [VAR=VALUE]...
@@ -1529,7 +1531,7 @@ fi
if test -n "$ac_init_help"; then
case $ac_init_help in
- short | recursive ) echo "Configuration of unbound 1.13.2:";;
+ short | recursive ) echo "Configuration of unbound 1.14.0rc1:";;
esac
cat <<\_ACEOF
@@ -1649,7 +1651,7 @@ Optional Packages:
--with-nettle=path use libnettle as crypto library, installed at path.
--with-ssl=pathname enable SSL (will check /usr/local/ssl /usr/lib/ssl
/usr/ssl /usr/pkg /usr/local /opt/local /usr/sfw
- /usr)
+ /usr or specify like /usr/include/openssl11)
--with-libbsd Use portable libbsd functions
--with-deprecate-rsa-1024
Deprecate RSA 1024 bit length, makes that an
@@ -1771,7 +1773,7 @@ fi
test -n "$ac_init_help" && exit $ac_status
if $ac_init_version; then
cat <<\_ACEOF
-unbound configure 1.13.2
+unbound configure 1.14.0rc1
generated by GNU Autoconf 2.69
Copyright (C) 2012 Free Software Foundation, Inc.
@@ -2480,7 +2482,7 @@ cat >config.log <<_ACEOF
This file contains any messages produced by compilers while
running configure, to aid debugging if configure makes a mistake.
-It was created by unbound $as_me 1.13.2, which was
+It was created by unbound $as_me 1.14.0rc1, which was
generated by GNU Autoconf 2.69. Invocation command line was
$ $0 $@
@@ -2830,13 +2832,13 @@ ac_compiler_gnu=$ac_cv_c_compiler_gnu
UNBOUND_VERSION_MAJOR=1
-UNBOUND_VERSION_MINOR=13
+UNBOUND_VERSION_MINOR=14
-UNBOUND_VERSION_MICRO=2
+UNBOUND_VERSION_MICRO=0rc1
LIBUNBOUND_CURRENT=9
-LIBUNBOUND_REVISION=13
+LIBUNBOUND_REVISION=14
LIBUNBOUND_AGE=1
# 1.0.0 had 0:12:0
# 1.0.1 had 0:13:0
@@ -2917,6 +2919,7 @@ LIBUNBOUND_AGE=1
# 1.13.0 had 9:11:1
# 1.13.1 had 9:12:1
# 1.13.2 had 9:13:1
+# 1.14.0 had 9:14:1
# Current -- the number of the binary API that we're implementing
# Revision -- which iteration of the implementation of the binary
@@ -15322,7 +15325,7 @@ if test "$ac_res" != no; then :
fi
-# check wether strptime also works
+# check whether strptime also works
# check some functions of the OS before linking libs (while still runnable).
for ac_header in unistd.h
@@ -17553,11 +17556,15 @@ ac_compiler_gnu=$ac_cv_c_compiler_gnu
$as_echo "#define HAVE_PYTHON 1" >>confdefs.h
- if test -n "$LIBS"; then
- LIBS="$PYTHON_LDFLAGS $LIBS"
- else
- LIBS="$PYTHON_LDFLAGS"
+ if test x_$ub_with_pythonmod != x_no; then
+ if test -n "$LIBS"; then
+ LIBS="$PYTHON_LDFLAGS $LIBS"
+ else
+ LIBS="$PYTHON_LDFLAGS"
+ fi
fi
+ PYTHON_LIBS="$PYTHON_LDFLAGS"
+
if test -n "$CPPFLAGS"; then
CPPFLAGS="$CPPFLAGS $PYTHON_CPPFLAGS"
else
@@ -17887,6 +17894,12 @@ if test "`uname`" = "NetBSD"; then
NETBSD_LINTFLAGS='"-D__RENAME(x)=" -D_NETINET_IN_H_'
fi
+
+if test "`uname -o`" = "GNU/Linux"; then
+ # splint cannot parse modern c99 header files
+ GCC_DOCKER_LINTFLAGS='-syntax'
+
+fi
CONFIG_DATE=`date +%Y%m%d`
@@ -17993,6 +18006,25 @@ fi
if test x_$withval != x_no; then
{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for SSL" >&5
$as_echo_n "checking for SSL... " >&6; }
+ if test -n "$withval"; then
+ if test ! -f "$withval/include/openssl/ssl.h" -a -f "$withval/openssl/ssl.h"; then
+ ssldir="$withval"
+ found_ssl="yes"
+ withval=""
+ ssldir_include="$ssldir"
+ ssldir_lib=`echo $ssldir | sed -e 's/include/lib/'`
+ if test -f "$ssldir_lib/libssl.a" -o -f "$ssldir_lib/libssl.so"; then
+ : # found here
+ else
+ ssldir_lib=`echo $ssldir | sed -e 's/include/lib64/'`
+ if test -f "$ssldir_lib/libssl.a" -o -f "$ssldir_lib/libssl.so"; then
+ : # found here
+ else
+ as_fn_error $? "Could not find openssl lib file, $ssldir_lib/libssl.so,a, pass like \"/usr/local\" or \"/usr/include/openssl11\"" "$LINENO" 5
+ fi
+ fi
+ fi
+ fi
if test x_$withval = x_ -o x_$withval = x_yes; then
withval="/usr/local/ssl /usr/lib/ssl /usr/ssl /usr/pkg /usr/local /opt/local /usr/sfw /usr"
fi
@@ -18000,15 +18032,12 @@ $as_echo_n "checking for SSL... " >&6; }
ssldir="$dir"
if test -f "$dir/include/openssl/ssl.h"; then
found_ssl="yes"
-
-cat >>confdefs.h <<_ACEOF
-#define HAVE_SSL /**/
-_ACEOF
-
- if test "$ssldir" != "/usr"; then
- CPPFLAGS="$CPPFLAGS -I$ssldir/include"
- LIBSSL_CPPFLAGS="$LIBSSL_CPPFLAGS -I$ssldir/include"
- fi
+ ssldir_include="$ssldir/include"
+ if test ! -d "$ssldir/lib" -a -d "$ssldir/lib64"; then
+ ssldir_lib="$ssldir/lib64"
+ else
+ ssldir_lib="$ssldir/lib"
+ fi
break;
fi
done
@@ -18017,30 +18046,25 @@ _ACEOF
else
{ $as_echo "$as_me:${as_lineno-$LINENO}: result: found in $ssldir" >&5
$as_echo "found in $ssldir" >&6; }
- HAVE_SSL=yes
- if test "$ssldir" != "/usr" -a "$ssldir" != ""; then
- if test ! -d "$ssldir/lib" -a -d "$ssldir/lib64"; then
- LDFLAGS="$LDFLAGS -L$ssldir/lib64"
- LIBSSL_LDFLAGS="$LIBSSL_LDFLAGS -L$ssldir/lib64"
- if test "x$enable_rpath" = xyes; then
- if echo "$ssldir/lib64" | grep "^/" >/dev/null; then
- RUNTIME_PATH="$RUNTIME_PATH -R$ssldir/lib64"
- fi
- fi
+cat >>confdefs.h <<_ACEOF
+#define HAVE_SSL /**/
+_ACEOF
- else
- LDFLAGS="$LDFLAGS -L$ssldir/lib"
- LIBSSL_LDFLAGS="$LIBSSL_LDFLAGS -L$ssldir/lib"
+ HAVE_SSL=yes
+ if test "$ssldir" != "/usr"; then
+ CPPFLAGS="$CPPFLAGS -I$ssldir_include"
+ LIBSSL_CPPFLAGS="$LIBSSL_CPPFLAGS -I$ssldir_include"
+ LDFLAGS="$LDFLAGS -L$ssldir_lib"
+ LIBSSL_LDFLAGS="$LIBSSL_LDFLAGS -L$ssldir_lib"
if test "x$enable_rpath" = xyes; then
- if echo "$ssldir/lib" | grep "^/" >/dev/null; then
- RUNTIME_PATH="$RUNTIME_PATH -R$ssldir/lib"
+ if echo "$ssldir_lib" | grep "^/" >/dev/null; then
+ RUNTIME_PATH="$RUNTIME_PATH -R$ssldir_lib"
fi
fi
- fi
- fi
+ fi
{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for EVP_sha256 in -lcrypto" >&5
$as_echo_n "checking for EVP_sha256 in -lcrypto... " >&6; }
@@ -18328,7 +18352,7 @@ rm -f core conftest.err conftest.$ac_objext \
conftest$ac_exeext conftest.$ac_ext
SSLLIB="-lssl"
-PC_CRYPTO_DEPENDENCY="libcrypto libssl"
+PC_CRYPTO_DEPENDENCY=""
# check if -lcrypt32 is needed because CAPIENG needs that. (on windows)
@@ -18369,7 +18393,7 @@ rm -f core conftest.err conftest.$ac_objext \
{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for LibreSSL" >&5
$as_echo_n "checking for LibreSSL... " >&6; }
-if grep VERSION_TEXT $ssldir/include/openssl/opensslv.h | grep "LibreSSL" >/dev/null; then
+if grep VERSION_TEXT $ssldir_include/openssl/opensslv.h | grep "LibreSSL" >/dev/null; then
{ $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5
$as_echo "yes" >&6; }
@@ -18436,7 +18460,7 @@ fi
done
-for ac_func in OPENSSL_config EVP_sha1 EVP_sha256 EVP_sha512 FIPS_mode EVP_MD_CTX_new OpenSSL_add_all_digests OPENSSL_init_crypto EVP_cleanup ENGINE_cleanup ERR_load_crypto_strings CRYPTO_cleanup_all_ex_data ERR_free_strings RAND_cleanup DSA_SIG_set0 EVP_dss1 EVP_DigestVerify EVP_aes_256_cbc EVP_EncryptInit_ex HMAC_Init_ex CRYPTO_THREADID_set_callback EVP_MAC_CTX_set_params OSSL_PARAM_BLD_new
+for ac_func in OPENSSL_config EVP_sha1 EVP_sha256 EVP_sha512 FIPS_mode EVP_MD_CTX_new OpenSSL_add_all_digests OPENSSL_init_crypto EVP_cleanup ENGINE_cleanup ERR_load_crypto_strings CRYPTO_cleanup_all_ex_data ERR_free_strings RAND_cleanup DSA_SIG_set0 EVP_dss1 EVP_DigestVerify EVP_aes_256_cbc EVP_EncryptInit_ex HMAC_Init_ex CRYPTO_THREADID_set_callback EVP_MAC_CTX_set_params OSSL_PARAM_BLD_new BIO_set_callback_ex
do :
as_ac_var=`$as_echo "ac_cv_func_$ac_func" | $as_tr_sh`
ac_fn_c_check_func "$LINENO" "$ac_func" "$as_ac_var"
@@ -18758,7 +18782,7 @@ $as_echo "#define CLIENT_SUBNET 1" >>confdefs.h
;;
esac
-# check wether gost also works
+# check whether gost also works
# Check whether --enable-gost was given.
if test "${enable_gost+set}" = set; then :
@@ -18791,7 +18815,7 @@ $as_echo_n "checking if GOST works... " >&6; }
if test c${cross_compiling} = cno; then
BAKCFLAGS="$CFLAGS"
if test -n "$ssldir"; then
- CFLAGS="$CFLAGS -Wl,-rpath,$ssldir/lib"
+ CFLAGS="$CFLAGS -Wl,-rpath,$ssldir_lib"
fi
if test "$cross_compiling" = yes; then :
{ { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5
@@ -18974,8 +18998,8 @@ fi
# see if OPENSSL 1.0.0 or later (has EVP MD and Verify independency)
{ $as_echo "$as_me:${as_lineno-$LINENO}: checking if openssl supports SHA2 and ECDSA with EVP" >&5
$as_echo_n "checking if openssl supports SHA2 and ECDSA with EVP... " >&6; }
- if grep OPENSSL_VERSION_TEXT $ssldir/include/openssl/opensslv.h | grep "OpenSSL" >/dev/null; then
- if grep OPENSSL_VERSION_NUMBER $ssldir/include/openssl/opensslv.h | grep 0x0 >/dev/null; then
+ if grep OPENSSL_VERSION_TEXT $ssldir_include/openssl/opensslv.h | grep "OpenSSL" >/dev/null; then
+ if grep OPENSSL_VERSION_NUMBER $ssldir_include/openssl/opensslv.h | grep 0x0 >/dev/null; then
{ $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
$as_echo "no" >&6; }
@@ -20398,7 +20422,7 @@ if test "$ac_res" != no; then :
fi
-for ac_func in tzset sigprocmask fcntl getpwnam endpwent getrlimit setrlimit setsid chroot kill chown sleep usleep random srandom recvmsg sendmsg writev socketpair glob initgroups strftime localtime_r setusercontext _beginthreadex endservent endprotoent fsync shmget accept4 getifaddrs
+for ac_func in tzset sigprocmask fcntl getpwnam endpwent getrlimit setrlimit setsid chroot kill chown sleep usleep random srandom recvmsg sendmsg writev socketpair glob initgroups strftime localtime_r setusercontext _beginthreadex endservent endprotoent fsync shmget accept4 getifaddrs if_nametoindex
do :
as_ac_var=`$as_echo "ac_cv_func_$ac_func" | $as_tr_sh`
ac_fn_c_check_func "$LINENO" "$ac_func" "$as_ac_var"
@@ -21816,7 +21840,7 @@ _ACEOF
-version=1.13.2
+version=1.14.0rc1
date=`date +'%b %e, %Y'`
@@ -22335,7 +22359,7 @@ cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1
# report actual input values of CONFIG_FILES etc. instead of their
# values after options handling.
ac_log="
-This file was extended by unbound $as_me 1.13.2, which was
+This file was extended by unbound $as_me 1.14.0rc1, which was
generated by GNU Autoconf 2.69. Invocation command line was
CONFIG_FILES = $CONFIG_FILES
@@ -22401,7 +22425,7 @@ _ACEOF
cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1
ac_cs_config="`$as_echo "$ac_configure_args" | sed 's/^ //; s/[\\""\`\$]/\\\\&/g'`"
ac_cs_version="\\
-unbound config.status 1.13.2
+unbound config.status 1.14.0rc1
configured by $0, generated by GNU Autoconf 2.69,
with options \\"\$ac_cs_config\\"
diff --git a/contrib/unbound/configure.ac b/contrib/unbound/configure.ac
index fe911723c87e..418ea099f6ad 100644
--- a/contrib/unbound/configure.ac
+++ b/contrib/unbound/configure.ac
@@ -10,15 +10,15 @@ sinclude(dnscrypt/dnscrypt.m4)
# must be numbers. ac_defun because of later processing
m4_define([VERSION_MAJOR],[1])
-m4_define([VERSION_MINOR],[13])
-m4_define([VERSION_MICRO],[2])
+m4_define([VERSION_MINOR],[14])
+m4_define([VERSION_MICRO],[0rc1])
AC_INIT([unbound],m4_defn([VERSION_MAJOR]).m4_defn([VERSION_MINOR]).m4_defn([VERSION_MICRO]),[unbound-bugs@nlnetlabs.nl or https://github.com/NLnetLabs/unbound/issues],[unbound])
AC_SUBST(UNBOUND_VERSION_MAJOR, [VERSION_MAJOR])
AC_SUBST(UNBOUND_VERSION_MINOR, [VERSION_MINOR])
AC_SUBST(UNBOUND_VERSION_MICRO, [VERSION_MICRO])
LIBUNBOUND_CURRENT=9
-LIBUNBOUND_REVISION=13
+LIBUNBOUND_REVISION=14
LIBUNBOUND_AGE=1
# 1.0.0 had 0:12:0
# 1.0.1 had 0:13:0
@@ -99,6 +99,7 @@ LIBUNBOUND_AGE=1
# 1.13.0 had 9:11:1
# 1.13.1 had 9:12:1
# 1.13.2 had 9:13:1
+# 1.14.0 had 9:14:1
# Current -- the number of the binary API that we're implementing
# Revision -- which iteration of the implementation of the binary
@@ -457,7 +458,7 @@ AC_SUBST(RUNTIME_PATH)
AC_SEARCH_LIBS([inet_pton], [nsl])
AC_SEARCH_LIBS([socket], [socket])
-# check wether strptime also works
+# check whether strptime also works
AC_DEFUN([AC_CHECK_STRPTIME_WORKS],
[AC_REQUIRE([AC_PROG_CC])
AC_MSG_CHECKING(whether strptime works)
@@ -699,11 +700,15 @@ if test x_$ub_test_python != x_no; then
AC_SUBST(PY_MAJOR_VERSION)
# Have Python
AC_DEFINE(HAVE_PYTHON,1,[Define if you have Python libraries and header files.])
- if test -n "$LIBS"; then
- LIBS="$PYTHON_LDFLAGS $LIBS"
- else
- LIBS="$PYTHON_LDFLAGS"
+ if test x_$ub_with_pythonmod != x_no; then
+ if test -n "$LIBS"; then
+ LIBS="$PYTHON_LDFLAGS $LIBS"
+ else
+ LIBS="$PYTHON_LDFLAGS"
+ fi
fi
+ PYTHON_LIBS="$PYTHON_LDFLAGS"
+ AC_SUBST(PYTHON_LIBS)
if test -n "$CPPFLAGS"; then
CPPFLAGS="$CPPFLAGS $PYTHON_CPPFLAGS"
else
@@ -776,6 +781,12 @@ if test "`uname`" = "NetBSD"; then
NETBSD_LINTFLAGS='"-D__RENAME(x)=" -D_NETINET_IN_H_'
AC_SUBST(NETBSD_LINTFLAGS)
fi
+
+if test "`uname -o`" = "GNU/Linux"; then
+ # splint cannot parse modern c99 header files
+ GCC_DOCKER_LINTFLAGS='-syntax'
+ AC_SUBST(GCC_DOCKER_LINTFLAGS)
+fi
CONFIG_DATE=`date +%Y%m%d`
AC_SUBST(CONFIG_DATE)
@@ -830,7 +841,7 @@ ACX_WITH_SSL
ACX_LIB_SSL
SSLLIB="-lssl"
-PC_CRYPTO_DEPENDENCY="libcrypto libssl"
+PC_CRYPTO_DEPENDENCY=""
AC_SUBST(PC_CRYPTO_DEPENDENCY)
# check if -lcrypt32 is needed because CAPIENG needs that. (on windows)
@@ -850,7 +861,7 @@ AC_LINK_IFELSE([AC_LANG_PROGRAM([[]], [[
])
AC_MSG_CHECKING([for LibreSSL])
-if grep VERSION_TEXT $ssldir/include/openssl/opensslv.h | grep "LibreSSL" >/dev/null; then
+if grep VERSION_TEXT $ssldir_include/openssl/opensslv.h | grep "LibreSSL" >/dev/null; then
AC_MSG_RESULT([yes])
AC_DEFINE([HAVE_LIBRESSL], [1], [Define if we have LibreSSL])
# libressl provides these compat functions, but they may also be
@@ -860,7 +871,7 @@ else
AC_MSG_RESULT([no])
fi
AC_CHECK_HEADERS([openssl/conf.h openssl/engine.h openssl/bn.h openssl/dh.h openssl/dsa.h openssl/rsa.h openssl/core_names.h openssl/param_build.h],,, [AC_INCLUDES_DEFAULT])
-AC_CHECK_FUNCS([OPENSSL_config EVP_sha1 EVP_sha256 EVP_sha512 FIPS_mode EVP_MD_CTX_new OpenSSL_add_all_digests OPENSSL_init_crypto EVP_cleanup ENGINE_cleanup ERR_load_crypto_strings CRYPTO_cleanup_all_ex_data ERR_free_strings RAND_cleanup DSA_SIG_set0 EVP_dss1 EVP_DigestVerify EVP_aes_256_cbc EVP_EncryptInit_ex HMAC_Init_ex CRYPTO_THREADID_set_callback EVP_MAC_CTX_set_params OSSL_PARAM_BLD_new])
+AC_CHECK_FUNCS([OPENSSL_config EVP_sha1 EVP_sha256 EVP_sha512 FIPS_mode EVP_MD_CTX_new OpenSSL_add_all_digests OPENSSL_init_crypto EVP_cleanup ENGINE_cleanup ERR_load_crypto_strings CRYPTO_cleanup_all_ex_data ERR_free_strings RAND_cleanup DSA_SIG_set0 EVP_dss1 EVP_DigestVerify EVP_aes_256_cbc EVP_EncryptInit_ex HMAC_Init_ex CRYPTO_THREADID_set_callback EVP_MAC_CTX_set_params OSSL_PARAM_BLD_new BIO_set_callback_ex])
# these check_funcs need -lssl
BAKLIBS="$LIBS"
@@ -973,14 +984,14 @@ case "$enable_subnet" in
;;
esac
-# check wether gost also works
+# check whether gost also works
AC_DEFUN([AC_CHECK_GOST_WORKS],
[AC_REQUIRE([AC_PROG_CC])
AC_MSG_CHECKING([if GOST works])
if test c${cross_compiling} = cno; then
BAKCFLAGS="$CFLAGS"
if test -n "$ssldir"; then
- CFLAGS="$CFLAGS -Wl,-rpath,$ssldir/lib"
+ CFLAGS="$CFLAGS -Wl,-rpath,$ssldir_lib"
fi
AC_RUN_IFELSE([AC_LANG_SOURCE([[
#include <string.h>
@@ -1103,8 +1114,8 @@ case "$enable_ecdsa" in
])
# see if OPENSSL 1.0.0 or later (has EVP MD and Verify independency)
AC_MSG_CHECKING([if openssl supports SHA2 and ECDSA with EVP])
- if grep OPENSSL_VERSION_TEXT $ssldir/include/openssl/opensslv.h | grep "OpenSSL" >/dev/null; then
- if grep OPENSSL_VERSION_NUMBER $ssldir/include/openssl/opensslv.h | grep 0x0 >/dev/null; then
+ if grep OPENSSL_VERSION_TEXT $ssldir_include/openssl/opensslv.h | grep "OpenSSL" >/dev/null; then
+ if grep OPENSSL_VERSION_NUMBER $ssldir_include/openssl/opensslv.h | grep 0x0 >/dev/null; then
AC_MSG_RESULT([no])
AC_DEFINE_UNQUOTED([USE_ECDSA_EVP_WORKAROUND], [1], [Define this to enable an EVP workaround for older openssl])
else
@@ -1594,7 +1605,7 @@ AC_LINK_IFELSE([AC_LANG_PROGRAM([
AC_MSG_RESULT(no))
AC_SEARCH_LIBS([setusercontext], [util])
-AC_CHECK_FUNCS([tzset sigprocmask fcntl getpwnam endpwent getrlimit setrlimit setsid chroot kill chown sleep usleep random srandom recvmsg sendmsg writev socketpair glob initgroups strftime localtime_r setusercontext _beginthreadex endservent endprotoent fsync shmget accept4 getifaddrs])
+AC_CHECK_FUNCS([tzset sigprocmask fcntl getpwnam endpwent getrlimit setrlimit setsid chroot kill chown sleep usleep random srandom recvmsg sendmsg writev socketpair glob initgroups strftime localtime_r setusercontext _beginthreadex endservent endprotoent fsync shmget accept4 getifaddrs if_nametoindex])
AC_CHECK_FUNCS([setresuid],,[AC_CHECK_FUNCS([setreuid])])
AC_CHECK_FUNCS([setresgid],,[AC_CHECK_FUNCS([setregid])])
diff --git a/contrib/unbound/contrib/Dockerfile.tests b/contrib/unbound/contrib/Dockerfile.tests
new file mode 100644
index 000000000000..417daccb21f9
--- /dev/null
+++ b/contrib/unbound/contrib/Dockerfile.tests
@@ -0,0 +1,11 @@
+FROM gcc:latest
+WORKDIR /usr/src/unbound
+RUN apt-get update
+# install semantic parser & lexical analyzer
+RUN apt-get install -y bison flex
+# install packages used in tests
+RUN apt-get install -y ldnsutils dnsutils xxd splint doxygen netcat
+# accept short rsa keys, which are used in tests
+RUN sed -i 's/SECLEVEL=2/SECLEVEL=1/g' /usr/lib/ssl/openssl.cnf
+
+CMD ["/bin/bash"]
diff --git a/contrib/unbound/contrib/drop2rpz b/contrib/unbound/contrib/drop2rpz
index 01602f651166..6ac9b492efe3 100644
--- a/contrib/unbound/contrib/drop2rpz
+++ b/contrib/unbound/contrib/drop2rpz
@@ -4,7 +4,7 @@
#
# unbound.conf:
# rpz:
-# name: "spamhaus-drop.rpz.local."
+# name: "drop.spamhaus.org.rpz.local."
# zonefile: "/path/tp/spamhaus-drop.rpz.local"
# rpz-log: yes
# rpz-log-name: "spamhaus-drop"
diff --git a/contrib/unbound/contrib/unbound.service.in b/contrib/unbound/contrib/unbound.service.in
index 90ee708ce2c5..ada5fac9c224 100644
--- a/contrib/unbound/contrib/unbound.service.in
+++ b/contrib/unbound/contrib/unbound.service.in
@@ -64,7 +64,8 @@ ProtectClock=true
ProtectControlGroups=true
ProtectKernelLogs=true
ProtectKernelModules=true
-ProtectKernelTunables=true
+# This breaks using socket options like 'so-rcvbuf'. Explicitly disable for visibility.
+ProtectKernelTunables=false
ProtectProc=invisible
ProtectSystem=strict
RuntimeDirectory=unbound
diff --git a/contrib/unbound/daemon/daemon.c b/contrib/unbound/daemon/daemon.c
index 6d666788325a..0e3923b4e9f2 100644
--- a/contrib/unbound/daemon/daemon.c
+++ b/contrib/unbound/daemon/daemon.c
@@ -210,7 +210,6 @@ daemon_init(void)
}
#endif /* USE_WINSOCK */
signal_handling_record();
- checklock_start();
#ifdef HAVE_SSL
# ifdef HAVE_ERR_LOAD_CRYPTO_STRINGS
ERR_load_crypto_strings();
@@ -280,6 +279,7 @@ daemon_init(void)
free(daemon);
return NULL;
}
+ listen_setup_locks();
if(gettimeofday(&daemon->time_boot, NULL) < 0)
log_err("gettimeofday: %s", strerror(errno));
daemon->time_last_stat = daemon->time_boot;
@@ -781,6 +781,7 @@ daemon_delete(struct daemon* daemon)
alloc_clear(&daemon->superalloc);
acl_list_delete(daemon->acl);
tcl_list_delete(daemon->tcl);
+ listen_desetup_locks();
free(daemon->chroot);
free(daemon->pidfile);
free(daemon->env);
diff --git a/contrib/unbound/daemon/remote.c b/contrib/unbound/daemon/remote.c
index 923ddefa4f29..adf0383895d4 100644
--- a/contrib/unbound/daemon/remote.c
+++ b/contrib/unbound/daemon/remote.c
@@ -813,7 +813,7 @@ print_mem(RES* ssl, struct worker* worker, struct daemon* daemon,
iter = mod_get_mem(&worker->env, "iterator");
respip = mod_get_mem(&worker->env, "respip");
#ifdef CLIENT_SUBNET
- subnet = mod_get_mem(&worker->env, "subnet");
+ subnet = mod_get_mem(&worker->env, "subnetcache");
#endif /* CLIENT_SUBNET */
#ifdef USE_IPSECMOD
ipsecmod = mod_get_mem(&worker->env, "ipsecmod");
diff --git a/contrib/unbound/daemon/stats.c b/contrib/unbound/daemon/stats.c
index 8720a52d6c6e..d08f18dbb137 100644
--- a/contrib/unbound/daemon/stats.c
+++ b/contrib/unbound/daemon/stats.c
@@ -137,7 +137,7 @@ static void
set_subnet_stats(struct worker* worker, struct ub_server_stats* svr,
int reset)
{
- int m = modstack_find(&worker->env.mesh->mods, "subnet");
+ int m = modstack_find(&worker->env.mesh->mods, "subnetcache");
struct subnet_env* sne;
if(m == -1)
return;
diff --git a/contrib/unbound/daemon/unbound.c b/contrib/unbound/daemon/unbound.c
index 934a96c8068b..457a08032857 100644
--- a/contrib/unbound/daemon/unbound.c
+++ b/contrib/unbound/daemon/unbound.c
@@ -781,6 +781,7 @@ main(int argc, char* argv[])
int cmdline_cfg = 0;
#endif
+ checklock_start();
log_init(NULL, 0, NULL);
log_ident_default = strrchr(argv[0],'/')?strrchr(argv[0],'/')+1:argv[0];
log_ident_set_default(log_ident_default);
diff --git a/contrib/unbound/daemon/worker.c b/contrib/unbound/daemon/worker.c
index e9e163a0448b..5d2483cd2cd9 100644
--- a/contrib/unbound/daemon/worker.c
+++ b/contrib/unbound/daemon/worker.c
@@ -146,7 +146,7 @@ worker_mem_report(struct worker* ATTR_UNUSED(worker),
(&worker->env, i);
#ifdef CLIENT_SUBNET
else if(strcmp(worker->env.mesh->mods.mod[i]->name,
- "subnet")==0)
+ "subnetcache")==0)
subnet += (*worker->env.mesh->mods.mod[i]->get_mem)
(&worker->env, i);
#endif /* CLIENT_SUBNET */
@@ -205,7 +205,7 @@ worker_mem_report(struct worker* ATTR_UNUSED(worker),
(&worker->env, i);
#ifdef CLIENT_SUBNET
else if(strcmp(worker->env.mesh->mods.mod[i]->name,
- "subnet")==0)
+ "subnetcache")==0)
subnet += (*worker->env.mesh->mods.mod[i]->get_mem)
(&worker->env, i);
#endif /* CLIENT_SUBNET */
@@ -449,7 +449,6 @@ answer_norec_from_cache(struct worker* worker, struct query_info* qinfo,
* Then check if it needs validation, if so, this routine fails,
* so that iterator can prime and validator can verify rrsets.
*/
- struct edns_data edns_bak;
uint16_t udpsize = edns->udp_size;
int secure = 0;
time_t timenow = *worker->env.now;
@@ -508,7 +507,6 @@ answer_norec_from_cache(struct worker* worker, struct query_info* qinfo,
}
}
/* return this delegation from the cache */
- edns_bak = *edns;
edns->edns_version = EDNS_ADVERTISED_VERSION;
edns->udp_size = EDNS_ADVERTISED_SIZE;
edns->ext_rcode = 0;
@@ -518,15 +516,13 @@ answer_norec_from_cache(struct worker* worker, struct query_info* qinfo,
worker->env.now_tv))
return 0;
msg->rep->flags |= BIT_QR|BIT_RA;
- if(!apply_edns_options(edns, &edns_bak, worker->env.cfg,
- repinfo->c, worker->scratchpad) ||
- !reply_info_answer_encode(&msg->qinfo, msg->rep, id, flags,
+ if(!reply_info_answer_encode(&msg->qinfo, msg->rep, id, flags,
repinfo->c->buffer, 0, 1, worker->scratchpad,
udpsize, edns, (int)(edns->bits & EDNS_DO), secure)) {
if(!inplace_cb_reply_servfail_call(&worker->env, qinfo, NULL, NULL,
LDNS_RCODE_SERVFAIL, edns, repinfo, worker->scratchpad,
worker->env.now_tv))
- edns->opt_list = NULL;
+ edns->opt_list_inplace_cb_out = NULL;
error_encode(repinfo->c->buffer, LDNS_RCODE_SERVFAIL,
&msg->qinfo, id, flags, edns);
}
@@ -604,7 +600,6 @@ answer_from_cache(struct worker* worker, struct query_info* qinfo,
struct reply_info* rep, uint16_t id, uint16_t flags,
struct comm_reply* repinfo, struct edns_data* edns)
{
- struct edns_data edns_bak;
time_t timenow = *worker->env.now;
uint16_t udpsize = edns->udp_size;
struct reply_info* encode_rep = rep;
@@ -685,7 +680,6 @@ answer_from_cache(struct worker* worker, struct query_info* qinfo,
}
} else *is_secure_answer = 0;
- edns_bak = *edns;
edns->edns_version = EDNS_ADVERTISED_VERSION;
edns->udp_size = EDNS_ADVERTISED_SIZE;
edns->ext_rcode = 0;
@@ -722,15 +716,13 @@ answer_from_cache(struct worker* worker, struct query_info* qinfo,
if(!*partial_repp)
goto bail_out;
}
- } else if(!apply_edns_options(edns, &edns_bak, worker->env.cfg,
- repinfo->c, worker->scratchpad) ||
- !reply_info_answer_encode(qinfo, encode_rep, id, flags,
+ } else if(!reply_info_answer_encode(qinfo, encode_rep, id, flags,
repinfo->c->buffer, timenow, 1, worker->scratchpad,
udpsize, edns, (int)(edns->bits & EDNS_DO), *is_secure_answer)) {
if(!inplace_cb_reply_servfail_call(&worker->env, qinfo, NULL, NULL,
LDNS_RCODE_SERVFAIL, edns, repinfo, worker->scratchpad,
worker->env.now_tv))
- edns->opt_list = NULL;
+ edns->opt_list_inplace_cb_out = NULL;
error_encode(repinfo->c->buffer, LDNS_RCODE_SERVFAIL,
qinfo, id, flags, edns);
}
@@ -789,6 +781,14 @@ chaos_replystr(sldns_buffer* pkt, char** str, int num, struct edns_data* edns,
int i;
unsigned int rd = LDNS_RD_WIRE(sldns_buffer_begin(pkt));
unsigned int cd = LDNS_CD_WIRE(sldns_buffer_begin(pkt));
+ size_t udpsize = edns->udp_size;
+ edns->edns_version = EDNS_ADVERTISED_VERSION;
+ edns->udp_size = EDNS_ADVERTISED_SIZE;
+ edns->bits &= EDNS_DO;
+ if(!inplace_cb_reply_local_call(&worker->env, NULL, NULL, NULL,
+ LDNS_RCODE_NOERROR, edns, repinfo, worker->scratchpad,
+ worker->env.now_tv))
+ edns->opt_list_inplace_cb_out = NULL;
sldns_buffer_clear(pkt);
sldns_buffer_skip(pkt, (ssize_t)sizeof(uint16_t)); /* skip id */
sldns_buffer_write_u16(pkt, (uint16_t)(BIT_QR|BIT_RA));
@@ -804,6 +804,12 @@ chaos_replystr(sldns_buffer* pkt, char** str, int num, struct edns_data* edns,
for(i=0; i<num; i++) {
size_t len = strlen(str[i]);
if(len>255) len=255; /* cap size of TXT record */
+ if(sldns_buffer_position(pkt)+2+2+2+4+2+1+len+
+ calc_edns_field_size(edns) > udpsize) {
+ sldns_buffer_write_u16_at(pkt, 6, i); /* ANCOUNT */
+ LDNS_TC_SET(sldns_buffer_begin(pkt));
+ break;
+ }
sldns_buffer_write_u16(pkt, 0xc00c); /* compr ptr to query */
sldns_buffer_write_u16(pkt, LDNS_RR_TYPE_TXT);
sldns_buffer_write_u16(pkt, LDNS_RR_CLASS_CH);
@@ -813,13 +819,6 @@ chaos_replystr(sldns_buffer* pkt, char** str, int num, struct edns_data* edns,
sldns_buffer_write(pkt, str[i], len);
}
sldns_buffer_flip(pkt);
- edns->edns_version = EDNS_ADVERTISED_VERSION;
- edns->udp_size = EDNS_ADVERTISED_SIZE;
- edns->bits &= EDNS_DO;
- if(!inplace_cb_reply_local_call(&worker->env, NULL, NULL, NULL,
- LDNS_RCODE_NOERROR, edns, repinfo, worker->scratchpad,
- worker->env.now_tv))
- edns->opt_list = NULL;
if(sldns_buffer_capacity(pkt) >=
sldns_buffer_limit(pkt)+calc_edns_field_size(edns))
attach_edns_record(pkt, edns);
@@ -1004,7 +1003,6 @@ answer_notify(struct worker* w, struct query_info* qinfo,
edns->udp_size = EDNS_ADVERTISED_SIZE;
edns->ext_rcode = 0;
edns->bits &= EDNS_DO;
- edns->opt_list = NULL;
error_encode(pkt, rcode, qinfo,
*(uint16_t*)(void *)sldns_buffer_begin(pkt),
sldns_buffer_read_u16_at(pkt, 2), edns);
@@ -1241,7 +1239,8 @@ worker_handle_request(struct comm_point* c, void* arg, int error,
}
goto send_reply;
}
- if((ret=parse_edns_from_pkt(c->buffer, &edns, worker->scratchpad)) != 0) {
+ if((ret=parse_edns_from_query_pkt(c->buffer, &edns, worker->env.cfg, c,
+ worker->scratchpad)) != 0) {
struct edns_data reply_edns;
verbose(VERB_ALGO, "worker parse edns: formerror.");
log_addr(VERB_CLIENT,"from",&repinfo->addr, repinfo->addrlen);
@@ -1256,13 +1255,14 @@ worker_handle_request(struct comm_point* c, void* arg, int error,
goto send_reply;
}
if(edns.edns_present) {
- struct edns_option* edns_opt;
if(edns.edns_version != 0) {
edns.ext_rcode = (uint8_t)(EDNS_RCODE_BADVERS>>4);
edns.edns_version = EDNS_ADVERTISED_VERSION;
edns.udp_size = EDNS_ADVERTISED_SIZE;
edns.bits &= EDNS_DO;
- edns.opt_list = NULL;
+ edns.opt_list_in = NULL;
+ edns.opt_list_out = NULL;
+ edns.opt_list_inplace_cb_out = NULL;
edns.padding_block_size = 0;
verbose(VERB_ALGO, "query with bad edns version.");
log_addr(VERB_CLIENT,"from",&repinfo->addr, repinfo->addrlen);
@@ -1282,26 +1282,6 @@ worker_handle_request(struct comm_point* c, void* arg, int error,
log_addr(VERB_CLIENT,"from",&repinfo->addr, repinfo->addrlen);
edns.udp_size = NORMAL_UDP_SIZE;
}
- if(c->type != comm_udp) {
- edns_opt = edns_opt_list_find(edns.opt_list, LDNS_EDNS_KEEPALIVE);
- if(edns_opt && edns_opt->opt_len > 0) {
- edns.ext_rcode = 0;
- edns.edns_version = EDNS_ADVERTISED_VERSION;
- edns.udp_size = EDNS_ADVERTISED_SIZE;
- edns.bits &= EDNS_DO;
- edns.opt_list = NULL;
- verbose(VERB_ALGO, "query with bad edns keepalive.");
- log_addr(VERB_CLIENT,"from",&repinfo->addr, repinfo->addrlen);
- error_encode(c->buffer, LDNS_RCODE_FORMERR, &qinfo,
- *(uint16_t*)(void *)sldns_buffer_begin(c->buffer),
- sldns_buffer_read_u16_at(c->buffer, 2), NULL);
- if(sldns_buffer_capacity(c->buffer) >=
- sldns_buffer_limit(c->buffer)+calc_edns_field_size(&edns))
- attach_edns_record(c->buffer, &edns);
- regional_free_all(worker->scratchpad);
- goto send_reply;
- }
- }
}
if(edns.udp_size > worker->daemon->cfg->max_udp_size &&
c->type == comm_udp) {
@@ -1355,7 +1335,7 @@ worker_handle_request(struct comm_point* c, void* arg, int error,
goto send_reply;
}
if(worker->env.auth_zones &&
- rpz_apply_qname_trigger(worker->env.auth_zones,
+ rpz_callback_from_worker_request(worker->env.auth_zones,
&worker->env, &qinfo, &edns, c->buffer, worker->scratchpad,
repinfo, acladdr->taglist, acladdr->taglen, &worker->stats)) {
regional_free_all(worker->scratchpad);
@@ -1453,7 +1433,7 @@ lookup_cache:
* this is a two-pass operation, and lookup_qinfo is different for
* each pass. We should still pass the original qinfo to
* answer_from_cache(), however, since it's used to build the reply. */
- if(!edns_bypass_cache_stage(edns.opt_list, &worker->env)) {
+ if(!edns_bypass_cache_stage(edns.opt_list_in, &worker->env)) {
is_expired_answer = 0;
is_secure_answer = 0;
h = query_info_hash(lookup_qinfo, sldns_buffer_read_u16_at(c->buffer, 2));
@@ -1988,8 +1968,8 @@ worker_delete(struct worker* worker)
struct outbound_entry*
worker_send_query(struct query_info* qinfo, uint16_t flags, int dnssec,
int want_dnssec, int nocaps, struct sockaddr_storage* addr,
- socklen_t addrlen, uint8_t* zone, size_t zonelen, int ssl_upstream,
- char* tls_auth_name, struct module_qstate* q)
+ socklen_t addrlen, uint8_t* zone, size_t zonelen, int tcp_upstream,
+ int ssl_upstream, char* tls_auth_name, struct module_qstate* q)
{
struct worker* worker = q->env->worker;
struct outbound_entry* e = (struct outbound_entry*)regional_alloc(
@@ -1998,7 +1978,7 @@ worker_send_query(struct query_info* qinfo, uint16_t flags, int dnssec,
return NULL;
e->qstate = q;
e->qsent = outnet_serviced_query(worker->back, qinfo, flags, dnssec,
- want_dnssec, nocaps, q->env->cfg->tcp_upstream,
+ want_dnssec, nocaps, tcp_upstream,
ssl_upstream, tls_auth_name, addr, addrlen, zone, zonelen, q,
worker_handle_service_reply, e, worker->back->udp_buff, q->env);
if(!e->qsent) {
@@ -2045,7 +2025,7 @@ struct outbound_entry* libworker_send_query(
uint16_t ATTR_UNUSED(flags), int ATTR_UNUSED(dnssec),
int ATTR_UNUSED(want_dnssec), int ATTR_UNUSED(nocaps),
struct sockaddr_storage* ATTR_UNUSED(addr), socklen_t ATTR_UNUSED(addrlen),
- uint8_t* ATTR_UNUSED(zone), size_t ATTR_UNUSED(zonelen),
+ uint8_t* ATTR_UNUSED(zone), size_t ATTR_UNUSED(zonelen), int ATTR_UNUSED(tcp_upstream),
int ATTR_UNUSED(ssl_upstream), char* ATTR_UNUSED(tls_auth_name),
struct module_qstate* ATTR_UNUSED(q))
{
diff --git a/contrib/unbound/dns64/dns64.c b/contrib/unbound/dns64/dns64.c
index c79bc9c65796..d01b436e1d6c 100644
--- a/contrib/unbound/dns64/dns64.c
+++ b/contrib/unbound/dns64/dns64.c
@@ -685,8 +685,12 @@ dns64_operate(struct module_qstate* qstate, enum module_ev event, int id,
switch(event) {
case module_event_new:
/* Tag this query as being new and fall through. */
- iq = (struct dns64_qstate*)regional_alloc(
- qstate->region, sizeof(*iq));
+ if (!(iq = (struct dns64_qstate*)regional_alloc(
+ qstate->region, sizeof(*iq)))) {
+ log_err("out of memory");
+ qstate->ext_state[id] = module_error;
+ return;
+ }
qstate->minfo[id] = iq;
iq->state = DNS64_NEW_QUERY;
iq->started_no_cache_store = qstate->no_cache_store;
@@ -913,8 +917,9 @@ dns64_adjust_ptr(struct module_qstate* qstate, struct module_qstate* super)
sizeof(struct dns_msg))))
return;
super->return_msg->qinfo = super->qinfo;
- super->return_msg->rep = reply_info_copy(qstate->return_msg->rep, NULL,
- super->region);
+ if (!(super->return_msg->rep = reply_info_copy(qstate->return_msg->rep,
+ NULL, super->region)))
+ return;
/*
* Adjust the domain name of the answer RR set so that it matches the
diff --git a/contrib/unbound/dnscrypt/dnscrypt.c b/contrib/unbound/dnscrypt/dnscrypt.c
index 9b324ae69052..4902447fda01 100644
--- a/contrib/unbound/dnscrypt/dnscrypt.c
+++ b/contrib/unbound/dnscrypt/dnscrypt.c
@@ -435,7 +435,7 @@ dnscrypt_hrtime(void)
/**
* Add the server nonce part to once.
- * The nonce is made half of client nonce and the seconf half of the server
+ * The nonce is made half of client nonce and the second half of the server
* nonce, both of them of size crypto_box_HALF_NONCEBYTES.
* \param[in] nonce: a uint8_t* of size crypto_box_NONCEBYTES
*/
@@ -674,7 +674,7 @@ dnsc_find_cert(struct dnsc_env* dnscenv, struct sldns_buffer* buffer)
/**
* Insert local-zone and local-data into configuration.
* In order to be able to serve certs over TXT, we can reuse the local-zone and
- * local-data config option. The zone and qname are infered from the
+ * local-data config option. The zone and qname are inferred from the
* provider_name and the content of the TXT record from the certificate content.
* returns the number of certificate TXT record that were loaded.
* < 0 in case of error.
diff --git a/contrib/unbound/dnscrypt/dnscrypt.h b/contrib/unbound/dnscrypt/dnscrypt.h
index 666f54e62aa4..b0da9b732681 100644
--- a/contrib/unbound/dnscrypt/dnscrypt.h
+++ b/contrib/unbound/dnscrypt/dnscrypt.h
@@ -114,7 +114,7 @@ void dnsc_delete(struct dnsc_env *env);
/**
* handle a crypted dnscrypt request.
- * Determine wether or not a query is coming over the dnscrypt listener and
+ * Determine whether or not a query is coming over the dnscrypt listener and
* attempt to uncurve it or detect if it is a certificate query.
* return 0 in case of failure.
*/
@@ -122,7 +122,7 @@ int dnsc_handle_curved_request(struct dnsc_env* dnscenv,
struct comm_reply* repinfo);
/**
* handle an unencrypted dnscrypt request.
- * Determine wether or not a query is going over the dnscrypt channel and
+ * Determine whether or not a query is going over the dnscrypt channel and
* attempt to curve it unless it was not crypted like when it is a
* certificate query.
* \return 0 in case of failure.
diff --git a/contrib/unbound/dnstap/dtstream.c b/contrib/unbound/dnstap/dtstream.c
index f1ace3c34023..14aacaef567b 100644
--- a/contrib/unbound/dnstap/dtstream.c
+++ b/contrib/unbound/dnstap/dtstream.c
@@ -251,7 +251,7 @@ dt_msg_queue_submit(struct dt_msg_queue* mq, void* buf, size_t len)
entry->buf = buf;
entry->len = len;
- /* aqcuire lock */
+ /* acquire lock */
lock_basic_lock(&mq->lock);
/* if list was empty, start timer for (eventual) wakeup */
if(mq->first == NULL)
@@ -930,7 +930,7 @@ static int dtio_write_more_of_data(struct dt_io_thread* dtio)
return 1;
}
-/** write more of the current messsage. false if incomplete, true if
+/** write more of the current message. false if incomplete, true if
* the message is done */
static int dtio_write_more(struct dt_io_thread* dtio)
{
@@ -1181,7 +1181,7 @@ static int dtio_read_accept_frame(struct dt_io_thread* dtio)
goto close_connection;
return 1;
} else {
- /* unknow content type */
+ /* unknown content type */
verbose(VERB_ALGO, "dnstap: ACCEPT frame "
"contains unknown content type, "
"closing connection");
diff --git a/contrib/unbound/dnstap/unbound-dnstap-socket.c b/contrib/unbound/dnstap/unbound-dnstap-socket.c
index 3de8ab3f0899..990b8a866af1 100644
--- a/contrib/unbound/dnstap/unbound-dnstap-socket.c
+++ b/contrib/unbound/dnstap/unbound-dnstap-socket.c
@@ -1264,9 +1264,9 @@ int main(int argc, char** argv)
memset(&tls_list, 0, sizeof(tls_list));
/* lock debug start (if any) */
+ checklock_start();
log_ident_set("unbound-dnstap-socket");
log_init(0, 0, 0);
- checklock_start();
#ifdef SIGPIPE
if(signal(SIGPIPE, SIG_IGN) == SIG_ERR) {
@@ -1415,8 +1415,9 @@ struct outbound_entry* worker_send_query(
int ATTR_UNUSED(dnssec), int ATTR_UNUSED(want_dnssec),
int ATTR_UNUSED(nocaps), struct sockaddr_storage* ATTR_UNUSED(addr),
socklen_t ATTR_UNUSED(addrlen), uint8_t* ATTR_UNUSED(zone),
- size_t ATTR_UNUSED(zonelen), int ATTR_UNUSED(ssl_upstream),
- char* ATTR_UNUSED(tls_auth_name), struct module_qstate* ATTR_UNUSED(q))
+ size_t ATTR_UNUSED(zonelen), int ATTR_UNUSED(tcp_upstream),
+ int ATTR_UNUSED(ssl_upstream), char* ATTR_UNUSED(tls_auth_name),
+ struct module_qstate* ATTR_UNUSED(q))
{
log_assert(0);
return 0;
@@ -1447,8 +1448,9 @@ struct outbound_entry* libworker_send_query(
int ATTR_UNUSED(dnssec), int ATTR_UNUSED(want_dnssec),
int ATTR_UNUSED(nocaps), struct sockaddr_storage* ATTR_UNUSED(addr),
socklen_t ATTR_UNUSED(addrlen), uint8_t* ATTR_UNUSED(zone),
- size_t ATTR_UNUSED(zonelen), int ATTR_UNUSED(ssl_upstream),
- char* ATTR_UNUSED(tls_auth_name), struct module_qstate* ATTR_UNUSED(q))
+ size_t ATTR_UNUSED(zonelen), int ATTR_UNUSED(tcp_upstream),
+ int ATTR_UNUSED(ssl_upstream), char* ATTR_UNUSED(tls_auth_name),
+ struct module_qstate* ATTR_UNUSED(q))
{
log_assert(0);
return 0;
diff --git a/contrib/unbound/doc/Changelog b/contrib/unbound/doc/Changelog
index 91abd0da0258..8aec7694f42d 100644
--- a/contrib/unbound/doc/Changelog
+++ b/contrib/unbound/doc/Changelog
@@ -1,3 +1,167 @@
+1 December 2021: Wouter
+ - configure is set to 1.14.0, and release branch.
+ - Fix doc/unbound.doxygen to remove obsolete tag warning.
+
+1 December 2021: George
+ - Merge PR #511 from yan12125: Reduce unnecessary linking.
+ - Merge PR #493 from Jaap: Fix generation of libunbound.pc.
+ - Merge PR #555 from fobser: Allow interface names as scope-id in IPv6
+ link-local addresses.
+ - Merge PR #562 from Willem: Reset keepalive per new tcp session.
+ - Merge PR #522 from sibeream: memory management violations fixed.
+ - Merge PR #530 from Shchelk: Fix: dereferencing a null pointer.
+ - Fix #454: listen_dnsport.c:825: error: ‘IPV6_TCLASS’ undeclared.
+ - Fix #574: Review fixes for size allocation.
+
+30 November 2021: Wouter
+ - Fix to remove git tracking and ci information from release tarballs.
+ - iana portlist update.
+
+29 November 2021: Wouter
+ - Merge PR #570 from rex4539: Fix typos.
+ - Fix for #570: regen aclocal.m4, fix configure.ac for spelling.
+ - Fix to make python module opt_list use opt_list_in.
+ - Fix #574: unbound-checkconf reports fatal error if interface names
+ are used as value for interfaces:
+ - Fix #574: Review fixes for it.
+ - Fix #576: [FR] UB_* error codes in unbound.h
+ - Fix #574: Review fix for spelling.
+
+15 November 2021: Tom
+ - Improve EDNS option handling, now also works for synthesised
+ responses such as local-data and server.id CH TXT responses.
+
+5 November 2021: George
+ - Fix for #558: fix loop in comm_point->tcp_free when a comm_point is
+ reclaimed more than once during callbacks.
+ - Fix for #558: clear the UB_EV_TIMEOUT bit before adding an event.
+
+5 November 2021: Wouter
+ - Fix that forward-zone name is documented as the full name of the
+ zone. It is not relative but a fully qualified domain name.
+ - Fix analyzer review failure in rpz action override code to not
+ crash on unlocking the local zone lock.
+ - Fix to remove unused code from rpz resolve client and action
+ function.
+ - Merge #565: unbound.service.in: Disable ProtectKernelTunables again.
+
+2 November 2021: Wouter
+ - Fix #552: Unbound assumes index.html exists on RPZ host.
+
+11 October 2021: Wouter
+ - Fix chaos replies to have truncation for short message lengths,
+ or long reply strings.
+ - Fix to protect custom regional create against small values.
+
+4 October 2021: Wouter
+ - Fix to add example.conf note for outbound-msg-retry.
+
+27 September 2021: Wouter
+ - Implement RFC8375: Special-Use Domain 'home.arpa.'.
+
+21 September 2021: Wouter
+ - For crosscompile on windows, detect 64bit stackprotector library.
+ - Fix crosscompile shell syntax.
+ - Fix crosscompile windows to use libssp when it exists.
+ - For the windows compile script disable gost.
+ - Fix that on windows, use BIO_set_callback_ex instead of deprecated
+ BIO_set_callback.
+ - Fix crosscompile script for the shared build flags.
+
+20 September 2021: Wouter
+ - Fix crosscompile on windows to work with openssl 3.0.0 the
+ link with ws2_32 needs -l:libssp.a for __strcpy_chk.
+ Also copy results from lib64 directory if needed.
+
+10 September 2021: Wouter
+ - Fix initialisation errors reported by gcc sanitizer.
+ - Fix lock debug code for gcc sanitizer reports.
+ - Fix more initialisation errors reported by gcc sanitizer.
+
+8 September 2021: Wouter
+ - Merged #41 from Moritz Schneider: made outbound-msg-retry
+ configurable.
+ - Small fixes for #41: changelog, conflicts resolved,
+ processQueryResponse takes an iterator env argument like other
+ functions in the iterator, no colon in string for set_option,
+ and some whitespace style, to make it similar to the rest.
+ - Fix for #41: change outbound retry to int to fix signed comparison
+ warnings.
+ - Fix root_anchor test to check with new icannbundle date.
+
+3 September 2021: Wouter
+ - Fix #538: Fix subnetcache statistics.
+
+1 September 2021: Wouter
+ - Fix tcp fastopen failure when disabled, try normal connect instead.
+
+27 August 2021: Wouter
+ - Fix #533: Negative responses get cached even when setting
+ cache-max-negative-ttl: 1
+
+25 August 2021: Wouter
+ - Merge #401: RPZ triggers. This add additional RPZ triggers,
+ unbound supports a full set of rpz triggers, and this now
+ includes nsdname, nsip and clientip triggers. Also actions
+ are fully supported, and this now includes the tcp-only action.
+ - Fix #536: error: RPZ: name of record (drop.spamhaus.org.rpz.local.)
+ to insert into RPZ.
+ - Fix the stream wait stream_wait_count_lock and http2 buffer locks
+ setup and desetup from race condition.
+ - Fix RPZ locks. Do not unlock zones lock if requested and rpz find
+ zone does not find the zone. Readlock the clientip that is found
+ for ipbased triggers. Unlock the nsdname zone lock when done.
+ Unlock zone and ip in rpz nsip and nsdname callback. Unlock
+ authzone and localzone if clientip found in rpz worker call.
+ - Fix compile warning in libunbound for listen desetup routine.
+ - Fix asynclook unit test for setup of lockchecks before log.
+
+20 August 2021: Wouter
+ - Fix #529: Fix: log_assert does nothing if UNBOUND_DEBUG is
+ undefined.
+ - Fix #531: Fix: passed to proc after free.
+
+17 August 2021: Wouter
+ - Fix that --with-ssl can use "/usr/include/openssl11" to pass the
+ location of a different openssl version.
+ - Fix #527: not sending quad9 cert to syslog (and may be more).
+ - Fix sed script in ssldir split handling.
+
+16 August 2021: George
+ - Merge PR #528 from fobser: Make sldns_str2wire_svcparam_buf()
+ static.
+
+16 August 2021: Wouter
+ - Fix to support harden-algo-downgrade for ZONEMD dnssec checks.
+
+13 August 2021: Wouter
+ - Support using system-wide crypto policies.
+ - Fix for #431: Squelch permission denied errors for udp connect,
+ and udp send, they are visible at higher verbosity settings.
+ - Fix zonemd verification of key that is not in DNS but in the zone
+ and needs a chain of trust.
+ - zonemd, fix order of bogus printout string manipulation.
+
+12 August 2021: George
+ - Merge PR #514, from ziollek: Docker environment for run tests.
+ - For #514: generate configure.
+
+12 August 2021: Wouter
+ - And 1.13.2rc1 became the 1.13.2 with the fix for the python module
+ build. The current code repository continues with version 1.13.3.
+ - Add test tool readzone to .gitignore.
+ - Merge #521: Update mini_event.c.
+ - Merge #523: fix: free() call more than once with the same pointer.
+ - Merge #519: Support for selective enabling tcp-upstream for
+ stub/forward zones.
+ - For #519: note stub-tcp-upstream and forward-tcp-upstream in
+ the example configuration file.
+ - For #519: yacc and lex. And fix python bindings, and test program
+ unbound-dnstap-socket.
+ - For #519: fix comments for doxygen.
+ - Fix to print error from unbound-anchor for writing to the key
+ file, also when not verbose.
+
5 August 2021: Wouter
- Tag for 1.13.2rc1 release.
- Fix #520: Unbound 1.13.2rc1 fails to build python module.
diff --git a/contrib/unbound/doc/README b/contrib/unbound/doc/README
index a051380e1d7b..ea18f4fe5c05 100644
--- a/contrib/unbound/doc/README
+++ b/contrib/unbound/doc/README
@@ -1,4 +1,4 @@
-README for Unbound 1.13.2
+README for Unbound 1.14.0rc1
Copyright 2007 NLnet Labs
http://unbound.net
diff --git a/contrib/unbound/doc/README.tests b/contrib/unbound/doc/README.tests
index 5385e2b2221f..376f01717fdd 100644
--- a/contrib/unbound/doc/README.tests
+++ b/contrib/unbound/doc/README.tests
@@ -15,6 +15,14 @@ You need to have the following programs installed and in your PATH.
* xxd and nc (optional) - for (malformed) packet transmission.
The optional programs are detected and can be omitted.
+You can also use prepared Dockerfile to run tests inside docker based on latest gcc image:
+* build container: docker build -t unbound-tester -f contrib/Dockerfile.tests .
+* run container: docker run -it --mount type=bind,source="$(pwd)",target=/usr/src/unbound --rm unbound-tester
+* configure environment: ./configure
+* run test: make test
+* run long tests: make longtest
+It is worth to mention that you need to enable [ipv6 in your docker daemon configuration](https://docs.docker.com/config/daemon/ipv6/) because some tests need ipv6 network stack.
+
testdata/ contains the data for tests.
testcode/ contains scripts and c code for the tests.
diff --git a/contrib/unbound/doc/example.conf.in b/contrib/unbound/doc/example.conf.in
index a0c002d2c386..2dfd770fd4c5 100644
--- a/contrib/unbound/doc/example.conf.in
+++ b/contrib/unbound/doc/example.conf.in
@@ -1,7 +1,7 @@
#
# Example configuration file.
#
-# See unbound.conf(5) man page, version 1.13.2.
+# See unbound.conf(5) man page, version 1.14.0rc1.
#
# this is a comment.
@@ -164,6 +164,9 @@ server:
# perform connect for UDP sockets to mitigate ICMP side channel.
# udp-connect: yes
+ # The number of retries when a non-positive response is received.
+ # outbound-msg-retry: 5
+
# msec for waiting for an unknown server to reply. Increase if you
# are behind a slow satellite link, to eg. 1128.
# unknown-server-time-limit: 376
@@ -666,6 +669,7 @@ server:
# local-zone: "localhost." nodefault
# local-zone: "127.in-addr.arpa." nodefault
# local-zone: "1.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.ip6.arpa." nodefault
+ # local-zone: "home.arpa." nodefault
# local-zone: "onion." nodefault
# local-zone: "test." nodefault
# local-zone: "invalid." nodefault
@@ -987,6 +991,7 @@ remote-control:
# stub-addr: 192.0.2.68
# stub-prime: no
# stub-first: no
+# stub-tcp-upstream: no
# stub-tls-upstream: no
# stub-no-cache: no
# stub-zone:
@@ -1004,6 +1009,7 @@ remote-control:
# forward-addr: 192.0.2.68
# forward-addr: 192.0.2.73@5355 # forward to port 5355.
# forward-first: no
+# forward-tcp-upstream: no
# forward-tls-upstream: no
# forward-no-cache: no
# forward-zone:
@@ -1150,10 +1156,11 @@ remote-control:
# dnstap-log-forwarder-response-messages: no
# Response Policy Zones
-# RPZ policies. Applied in order of configuration. QNAME and Response IP
-# Address trigger are the only supported triggers. Supported actions are:
-# NXDOMAIN, NODATA, PASSTHRU, DROP and Local Data. Policies can be loaded from
-# file, using zone transfer, or using HTTP. The respip module needs to be added
+# RPZ policies. Applied in order of configuration. QNAME, Response IP
+# Address, nsdname, nsip and clientip triggers are supported. Supported
+# actions are: NXDOMAIN, NODATA, PASSTHRU, DROP, Local Data, tcp-only
+# and drop. Policies can be loaded from a file, or using zone
+# transfer, or using HTTP. The respip module needs to be added
# to the module-config, e.g.: module-config: "respip validator iterator".
# rpz:
# name: "rpz.example.com"
diff --git a/contrib/unbound/doc/libunbound.3.in b/contrib/unbound/doc/libunbound.3.in
index 73562cd6b41f..a35b41bf0525 100644
--- a/contrib/unbound/doc/libunbound.3.in
+++ b/contrib/unbound/doc/libunbound.3.in
@@ -1,4 +1,4 @@
-.TH "libunbound" "3" "Aug 12, 2021" "NLnet Labs" "unbound 1.13.2"
+.TH "libunbound" "3" "Dec 2, 2021" "NLnet Labs" "unbound 1.14.0rc1"
.\"
.\" libunbound.3 -- unbound library functions manual
.\"
@@ -44,7 +44,7 @@
.B ub_ctx_zone_remove,
.B ub_ctx_data_add,
.B ub_ctx_data_remove
-\- Unbound DNS validating resolver 1.13.2 functions.
+\- Unbound DNS validating resolver 1.14.0rc1 functions.
.SH "SYNOPSIS"
.B #include <unbound.h>
.LP
diff --git a/contrib/unbound/doc/unbound-anchor.8.in b/contrib/unbound/doc/unbound-anchor.8.in
index 25f7f1baf147..84d6f348c484 100644
--- a/contrib/unbound/doc/unbound-anchor.8.in
+++ b/contrib/unbound/doc/unbound-anchor.8.in
@@ -1,4 +1,4 @@
-.TH "unbound-anchor" "8" "Aug 12, 2021" "NLnet Labs" "unbound 1.13.2"
+.TH "unbound-anchor" "8" "Dec 2, 2021" "NLnet Labs" "unbound 1.14.0rc1"
.\"
.\" unbound-anchor.8 -- unbound anchor maintenance utility manual
.\"
diff --git a/contrib/unbound/doc/unbound-checkconf.8.in b/contrib/unbound/doc/unbound-checkconf.8.in
index e9b8ba2d60c0..2453a1984532 100644
--- a/contrib/unbound/doc/unbound-checkconf.8.in
+++ b/contrib/unbound/doc/unbound-checkconf.8.in
@@ -1,4 +1,4 @@
-.TH "unbound-checkconf" "8" "Aug 12, 2021" "NLnet Labs" "unbound 1.13.2"
+.TH "unbound-checkconf" "8" "Dec 2, 2021" "NLnet Labs" "unbound 1.14.0rc1"
.\"
.\" unbound-checkconf.8 -- unbound configuration checker manual
.\"
diff --git a/contrib/unbound/doc/unbound-control.8.in b/contrib/unbound/doc/unbound-control.8.in
index fb3510fa3cb5..d268b0b94b7e 100644
--- a/contrib/unbound/doc/unbound-control.8.in
+++ b/contrib/unbound/doc/unbound-control.8.in
@@ -1,4 +1,4 @@
-.TH "unbound-control" "8" "Aug 12, 2021" "NLnet Labs" "unbound 1.13.2"
+.TH "unbound-control" "8" "Dec 2, 2021" "NLnet Labs" "unbound 1.14.0rc1"
.\"
.\" unbound-control.8 -- unbound remote control manual
.\"
@@ -684,8 +684,8 @@ specific cache, after getting processed by the edns client subnet module.
.TP
.I num.rpz.action.<rpz_action>
Number of queries answered using configured RPZ policy, per RPZ action type.
-Possible actions are: nxdomain, nodata, passthru, drop, local_data, disabled,
-and cname_override.
+Possible actions are: nxdomain, nodata, passthru, drop, tcp\-only, local\-data,
+disabled, and cname\-override.
.SH "FILES"
.TP
.I @ub_conf_file@
diff --git a/contrib/unbound/doc/unbound-host.1.in b/contrib/unbound/doc/unbound-host.1.in
index 4823b9afcaf5..85863835b505 100644
--- a/contrib/unbound/doc/unbound-host.1.in
+++ b/contrib/unbound/doc/unbound-host.1.in
@@ -1,4 +1,4 @@
-.TH "unbound\-host" "1" "Aug 12, 2021" "NLnet Labs" "unbound 1.13.2"
+.TH "unbound\-host" "1" "Dec 2, 2021" "NLnet Labs" "unbound 1.14.0rc1"
.\"
.\" unbound-host.1 -- unbound DNS lookup utility
.\"
diff --git a/contrib/unbound/doc/unbound.8.in b/contrib/unbound/doc/unbound.8.in
index 82c4e98eb191..6f956b6a184d 100644
--- a/contrib/unbound/doc/unbound.8.in
+++ b/contrib/unbound/doc/unbound.8.in
@@ -1,4 +1,4 @@
-.TH "unbound" "8" "Aug 12, 2021" "NLnet Labs" "unbound 1.13.2"
+.TH "unbound" "8" "Dec 2, 2021" "NLnet Labs" "unbound 1.14.0rc1"
.\"
.\" unbound.8 -- unbound manual
.\"
@@ -9,7 +9,7 @@
.\"
.SH "NAME"
.B unbound
-\- Unbound DNS validating resolver 1.13.2.
+\- Unbound DNS validating resolver 1.14.0rc1.
.SH "SYNOPSIS"
.B unbound
.RB [ \-h ]
diff --git a/contrib/unbound/doc/unbound.conf.5.in b/contrib/unbound/doc/unbound.conf.5.in
index e44560ec9eb6..baf024b70960 100644
--- a/contrib/unbound/doc/unbound.conf.5.in
+++ b/contrib/unbound/doc/unbound.conf.5.in
@@ -1,4 +1,4 @@
-.TH "unbound.conf" "5" "Aug 12, 2021" "NLnet Labs" "unbound 1.13.2"
+.TH "unbound.conf" "5" "Dec 2, 2021" "NLnet Labs" "unbound 1.14.0rc1"
.\"
.\" unbound.conf.5 -- unbound.conf manual
.\"
@@ -485,7 +485,9 @@ advertised timeout.
.TP
.B tcp\-upstream: \fI<yes or no>
Enable or disable whether the upstream queries use TCP only for transport.
-Default is no. Useful in tunneling scenarios.
+Default is no. Useful in tunneling scenarios. If set to no you can specify
+TCP transport only for selected forward or stub zones using forward-tcp-upstream
+or stub-tcp-upstream respectively.
.TP
.B udp\-upstream\-without\-downstream: \fI<yes or no>
Enable udp upstream even if do-udp is no. Default is no, and this does not
@@ -1410,13 +1412,13 @@ has no other effect than turning off default contents for the
given zone. Use \fInodefault\fR if you use exactly that zone, if you want to
use a subzone, use \fItransparent\fR.
.P
-The default zones are localhost, reverse 127.0.0.1 and ::1, the onion, test,
-invalid and the AS112 zones. The AS112 zones are reverse DNS zones for
-private use and reserved IP addresses for which the servers on the internet
-cannot provide correct answers. They are configured by default to give
-nxdomain (no reverse information) answers. The defaults can be turned off
-by specifying your own local\-zone of that name, or using the 'nodefault'
-type. Below is a list of the default zone contents.
+The default zones are localhost, reverse 127.0.0.1 and ::1, the home.arpa,
+the onion, test, invalid and the AS112 zones. The AS112 zones are reverse
+DNS zones for private use and reserved IP addresses for which the servers
+on the internet cannot provide correct answers. They are configured by
+default to give nxdomain (no reverse information) answers. The defaults
+can be turned off by specifying your own local\-zone of that name, or
+using the 'nodefault' type. Below is a list of the default zone contents.
.TP 10
\h'5'\fIlocalhost\fR
The IP4 and IP6 localhost information is given. NS and SOA records are provided
@@ -1457,6 +1459,15 @@ local\-data: "1.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.
PTR localhost."
.fi
.TP 10
+\h'5'\fIhome.arpa (RFC 8375)\fR
+Default content:
+.nf
+local\-zone: "home.arpa." static
+local\-data: "home.arpa. 10800 IN NS localhost."
+local\-data: "home.arpa. 10800 IN
+ SOA localhost. nobody.invalid. 1 3600 1200 604800 10800"
+.fi
+.TP 10
\h'5'\fIonion (RFC 7686)\fR
Default content:
.nf
@@ -1702,6 +1713,11 @@ This can make ordinary queries complete (if repeatedly queried for),
and enter the cache, whilst also mitigating the traffic flow by the
factor given.
.TP 5
+.B outbound\-msg\-retry: \fI<number>
+The number of retries unbound will do in case of a non positive response is
+received. If a forward nameserver is used, this is the number of retries per
+forward nameserver in case of throwaway response.
+.TP 5
.B fast\-server\-permil: \fI<number>
Specify how many times out of 1000 to pick from the set of fastest servers.
0 turns the feature off. A value of 900 would pick from the fastest
@@ -1822,7 +1838,7 @@ zone. The local zone nodefault (or \fItransparent\fR) clause makes the
(reverse\-) zone bypass unbound's filtering of RFC1918 zones.
.TP
.B name: \fI<domain name>
-Name of the stub zone.
+Name of the stub zone. This is the full domain name of the zone.
.TP
.B stub\-host: \fI<domain name>
Name of stub zone nameserver. Is itself resolved before it is used.
@@ -1853,6 +1869,10 @@ Default is no.
.B stub\-ssl\-upstream: \fI<yes or no>
Alternate syntax for \fBstub\-tls\-upstream\fR.
.TP
+.B stub\-tcp\-upstream: \fI<yes or no>
+If it is set to "yes" then upstream queries use TCP only for transport regardless of global flag tcp-upstream.
+Default is no.
+.TP
.B stub\-no\-cache: \fI<yes or no>
Default is no. If enabled, data inside the stub is not cached. This is
useful when you want immediate changes to be visible.
@@ -1875,7 +1895,7 @@ forward all queries to that other server (unless it can answer from
the cache).
.TP
.B name: \fI<domain name>
-Name of the forward zone.
+Name of the forward zone. This is the full domain name of the zone.
.TP
.B forward\-host: \fI<domain name>
Name of server to forward to. Is itself resolved before it is used.
@@ -1905,6 +1925,10 @@ load CA certs, otherwise the connections cannot be authenticated.
.B forward\-ssl\-upstream: \fI<yes or no>
Alternate syntax for \fBforward\-tls\-upstream\fR.
.TP
+.B forward\-tcp\-upstream: \fI<yes or no>
+If it is set to "yes" then upstream queries use TCP only for transport regardless of global flag tcp-upstream.
+Default is no.
+.TP
.B forward\-no\-cache: \fI<yes or no>
Default is no. If enabled, data inside the forward is not cached. This is
useful when you want immediate changes to be visible.
@@ -2391,7 +2415,7 @@ This option defaults to "default".
.P
The following
.B cachedb
-otions are specific to the redis backend.
+options are specific to the redis backend.
.TP
.B redis-server-host: \fI<server address or name>\fR
The IP (either v6 or v4) address or domain name of the Redis server.
@@ -2506,10 +2530,49 @@ with a different name. RPZ clauses are applied in order of configuration. The
\fBrespip\fR module needs to be added to the \fBmodule-config\fR, e.g.:
\fBmodule-config: "respip validator iterator"\fR.
.P
-Only the QNAME and Response IP Address triggers are supported. The supported RPZ
-actions are: NXDOMAIN, NODATA, PASSTHRU, DROP and Local Data. RPZ QNAME triggers
-are applied after
-\fBlocal-zones\fR and before \fBauth-zones\fR.
+QNAME, Response IP Address, nsdname, nsip and clientip triggers are supported.
+Supported actions are: NXDOMAIN, NODATA, PASSTHRU, DROP, Local Data, tcp\-only
+and drop. RPZ QNAME triggers are applied after \fBlocal\-zones\fR and
+before \fBauth\-zones\fR.
+.P
+The rpz zone is formatted with a SOA start record as usual. The items in
+the zone are entries, that specify what to act on (the trigger) and what to
+do (the action). The trigger to act on is recorded in the name, the action
+to do is recorded as the resource record. The names all end in the zone
+name, so you could type the trigger names without a trailing dot in the
+zonefile.
+.P
+An example RPZ record, that answers example.com with NXDOMAIN
+.nf
+ example.com CNAME .
+.fi
+.P
+The triggers are encoded in the name on the left
+.nf
+ name query name
+ netblock.rpz-client-ip client IP address
+ netblock.rpz-ip response IP address in the answer
+ name.rpz-nsdname nameserver name
+ netblock.rpz-nsip nameserver IP address
+.fi
+The netblock is written as <netblocklen>.<ip address in reverse>.
+For IPv6 use 'zz' for '::'. Specify individual addresses with scope length
+of 32 or 128. For example, 24.10.100.51.198.rpz-ip is 198.51.100.10/24 and
+32.10.zz.db8.2001.rpz-ip is 2001:db8:0:0:0:0:0:10/32.
+.P
+The actions are specified with the record on the right
+.nf
+ CNAME . nxdomain reply
+ CNAME *. nodata reply
+ CNAME rpz-passthru. do nothing, allow to continue
+ CNAME rpz-drop. the query is dropped
+ CNAME rpz-tcp-only. answer over TCP
+ A 192.0.2.1 answer with this IP address
+.fi
+Other records like AAAA, TXT and other CNAMEs (not rpz-..) can also be used to
+answer queries with that content.
+.P
+The RPZ zones can be configured in the config file with these settings in the \fBrpz:\fR block.
.TP
.B name: \fI<zone name>
Name of the authority zone.
diff --git a/contrib/unbound/doc/unbound.doxygen b/contrib/unbound/doc/unbound.doxygen
index 823e092536e4..7222dbc274e9 100644
--- a/contrib/unbound/doc/unbound.doxygen
+++ b/contrib/unbound/doc/unbound.doxygen
@@ -279,10 +279,10 @@ TYPEDEF_HIDES_STRUCT = NO
# For small to medium size projects (<1000 input files) the default value is
# probably good enough. For larger projects a too small cache size can cause
# doxygen to be busy swapping symbols to and from disk most of the time
-# causing a significant performance penality.
+# causing a significant performance penalty.
# If the system has enough physical memory increasing the cache will improve the
# performance by keeping more symbols in memory. Note that the value works on
-# a logarithmic scale so increasing the size by one will rougly double the
+# a logarithmic scale so increasing the size by one will roughly double the
# memory usage. The cache size is given by this formula:
# 2^(16+SYMBOL_CACHE_SIZE). The valid range is 0..9, the default is 0,
# corresponding to a cache size of 2^16 = 65536 symbols
@@ -779,7 +779,7 @@ ALPHABETICAL_INDEX = YES
# the COLS_IN_ALPHA_INDEX tag can be used to specify the number of columns
# in which this list will be split (can be a number in the range [1..20])
-COLS_IN_ALPHA_INDEX = 5
+#COLS_IN_ALPHA_INDEX = 5
# In case all classes in a project start with a common prefix, all
# classes will be put under the same header in the alphabetical index.
diff --git a/contrib/unbound/edns-subnet/edns-subnet.h b/contrib/unbound/edns-subnet/edns-subnet.h
index 4b306080ad6d..6ab541de9487 100644
--- a/contrib/unbound/edns-subnet/edns-subnet.h
+++ b/contrib/unbound/edns-subnet/edns-subnet.h
@@ -59,7 +59,7 @@ struct ecs_data {
/**
* copy the first n BITS from src to dst iff both src and dst
- * are large enough, return 0 on succes
+ * are large enough, return 0 on success
*/
int
copy_clear(uint8_t* dst, size_t dstlen, uint8_t* src, size_t srclen, size_t n);
diff --git a/contrib/unbound/edns-subnet/subnetmod.c b/contrib/unbound/edns-subnet/subnetmod.c
index ade40c66e85f..81f0bf3ade55 100644
--- a/contrib/unbound/edns-subnet/subnetmod.c
+++ b/contrib/unbound/edns-subnet/subnetmod.c
@@ -497,7 +497,7 @@ eval_response(struct module_qstate *qstate, int id, struct subnet_qstate *sq)
if (!s_in->subnet_validdata) {
/* The authority indicated no support for edns subnet. As a
* consequence the answer ended up in the regular cache. It
- * is still usefull to put it in the edns subnet cache for
+ * is still useful to put it in the edns subnet cache for
* when a client explicitly asks for subnet specific answer. */
verbose(VERB_QUERY, "subnetcache: Authority indicates no support");
if(!sq->started_no_cache_store) {
diff --git a/contrib/unbound/ipsecmod/ipsecmod.c b/contrib/unbound/ipsecmod/ipsecmod.c
index e42af6f497ea..577f7112e194 100644
--- a/contrib/unbound/ipsecmod/ipsecmod.c
+++ b/contrib/unbound/ipsecmod/ipsecmod.c
@@ -37,7 +37,7 @@
* \file
*
* This file contains a module that facilitates opportunistic IPsec. It does so
- * by also quering for the IPSECKEY for A/AAAA queries and calling a
+ * by also querying for the IPSECKEY for A/AAAA queries and calling a
* configurable hook (eg. signaling an IKE daemon) before replying.
*/
diff --git a/contrib/unbound/ipsecmod/ipsecmod.h b/contrib/unbound/ipsecmod/ipsecmod.h
index e00816d4bf99..272f473c2eac 100644
--- a/contrib/unbound/ipsecmod/ipsecmod.h
+++ b/contrib/unbound/ipsecmod/ipsecmod.h
@@ -37,7 +37,7 @@
* \file
*
* This file contains a module that facilitates opportunistic IPsec. It does so
- * by also quering for the IPSECKEY for A/AAAA queries and calling a
+ * by also querying for the IPSECKEY for A/AAAA queries and calling a
* configurable hook (eg. signaling an IKE daemon) before replying.
*/
diff --git a/contrib/unbound/iterator/iter_delegpt.c b/contrib/unbound/iterator/iter_delegpt.c
index 9a672b0af39d..bdac42b0ddb3 100644
--- a/contrib/unbound/iterator/iter_delegpt.c
+++ b/contrib/unbound/iterator/iter_delegpt.c
@@ -73,6 +73,7 @@ struct delegpt* delegpt_copy(struct delegpt* dp, struct regional* region)
copy->bogus = dp->bogus;
copy->has_parent_side_NS = dp->has_parent_side_NS;
copy->ssl_upstream = dp->ssl_upstream;
+ copy->tcp_upstream = dp->tcp_upstream;
for(ns = dp->nslist; ns; ns = ns->next) {
if(!delegpt_add_ns(copy, region, ns->name, ns->lame))
return NULL;
diff --git a/contrib/unbound/iterator/iter_delegpt.h b/contrib/unbound/iterator/iter_delegpt.h
index 138eb6e1b60a..9c8cfb281bae 100644
--- a/contrib/unbound/iterator/iter_delegpt.h
+++ b/contrib/unbound/iterator/iter_delegpt.h
@@ -83,6 +83,8 @@ struct delegpt {
uint8_t dp_type_mlc;
/** use SSL for upstream query */
uint8_t ssl_upstream;
+ /** use TCP for upstream query */
+ uint8_t tcp_upstream;
/** delegpt from authoritative zone that is locally hosted */
uint8_t auth_dp;
/*** no cache */
diff --git a/contrib/unbound/iterator/iter_fwd.c b/contrib/unbound/iterator/iter_fwd.c
index ea3d70e07320..128007a0412c 100644
--- a/contrib/unbound/iterator/iter_fwd.c
+++ b/contrib/unbound/iterator/iter_fwd.c
@@ -276,6 +276,8 @@ read_forwards(struct iter_forwards* fwd, struct config_file* cfg)
dp->no_cache = s->no_cache;
/* use SSL for queries to this forwarder */
dp->ssl_upstream = (uint8_t)s->ssl_upstream;
+ /* use TCP for queries to this forwarder */
+ dp->tcp_upstream = (uint8_t)s->tcp_upstream;
verbose(VERB_QUERY, "Forward zone server list:");
delegpt_log(VERB_QUERY, dp);
if(!forwards_insert(fwd, LDNS_RR_CLASS_IN, dp))
diff --git a/contrib/unbound/iterator/iter_hints.c b/contrib/unbound/iterator/iter_hints.c
index 60e518122ed1..5819cfb1703d 100644
--- a/contrib/unbound/iterator/iter_hints.c
+++ b/contrib/unbound/iterator/iter_hints.c
@@ -287,6 +287,8 @@ read_stubs(struct iter_hints* hints, struct config_file* cfg)
dp->no_cache = s->no_cache;
/* ssl_upstream */
dp->ssl_upstream = (uint8_t)s->ssl_upstream;
+ /* tcp_upstream */
+ dp->tcp_upstream = (uint8_t)s->tcp_upstream;
delegpt_log(VERB_QUERY, dp);
if(!hints_insert(hints, LDNS_RR_CLASS_IN, dp, !s->isprime))
return 0;
@@ -395,10 +397,10 @@ read_root_hints(struct iter_hints* hints, char* fname)
delegpt_free_mlc(dp);
return 1;
}
+ delegpt_log(VERB_QUERY, dp);
if(!hints_insert(hints, c, dp, 0)) {
return 0;
}
- delegpt_log(VERB_QUERY, dp);
return 1;
stop_read:
diff --git a/contrib/unbound/iterator/iter_utils.c b/contrib/unbound/iterator/iter_utils.c
index 668f898eb0ff..2482a1f40f03 100644
--- a/contrib/unbound/iterator/iter_utils.c
+++ b/contrib/unbound/iterator/iter_utils.c
@@ -4,22 +4,22 @@
* Copyright (c) 2007, NLnet Labs. All rights reserved.
*
* This software is open source.
- *
+ *
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
- *
+ *
* Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
- *
+ *
* Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
- *
+ *
* Neither the name of the NLNET LABS nor the names of its contributors may
* be used to endorse or promote products derived from this software without
* specific prior written permission.
- *
+ *
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
@@ -37,7 +37,7 @@
* \file
*
* This file contains functions to assist the iterator module.
- * Configuration options. Forward zones.
+ * Configuration options. Forward zones.
*/
#include "config.h"
#include "iterator/iter_utils.h"
@@ -141,7 +141,7 @@ caps_white_apply_cfg(rbtree_type* ntree, struct config_file* cfg)
return 1;
}
-int
+int
iter_apply_cfg(struct iter_env* iter_env, struct config_file* cfg)
{
int i;
@@ -151,7 +151,7 @@ iter_apply_cfg(struct iter_env* iter_env, struct config_file* cfg)
for(i=0; i<iter_env->max_dependency_depth+1; i++)
verbose(VERB_QUERY, "target fetch policy for level %d is %d",
i, iter_env->target_fetch_policy[i]);
-
+
if(!iter_env->donotq)
iter_env->donotq = donotq_create();
if(!iter_env->donotq || !donotq_apply_cfg(iter_env->donotq, cfg)) {
@@ -176,6 +176,7 @@ iter_apply_cfg(struct iter_env* iter_env, struct config_file* cfg)
}
iter_env->supports_ipv6 = cfg->do_ip6;
iter_env->supports_ipv4 = cfg->do_ip4;
+ iter_env->outbound_msg_retry = cfg->outbound_msg_retry;
return 1;
}
@@ -212,7 +213,7 @@ iter_apply_cfg(struct iter_env* iter_env, struct config_file* cfg)
* dnsseclame servers get penalty
* USEFUL_SERVER_TOP_TIMEOUT*3 ..
* recursion lame servers get penalty
- * UNKNOWN_SERVER_NICENESS
+ * UNKNOWN_SERVER_NICENESS
* If no information is known about the server, this is
* returned. 376 msec or so.
* +BLACKLIST_PENALTY (of USEFUL_TOP_TIMEOUT*4) for dnssec failed IPs.
@@ -221,11 +222,11 @@ iter_apply_cfg(struct iter_env* iter_env, struct config_file* cfg)
* is turned off (so we do not discard the reply).
* When a final value is chosen that is recursionlame; RD bit is set on query.
* Because of the numbers this means recursionlame also have dnssec lameness
- * checking turned off.
+ * checking turned off.
*/
static int
iter_filter_unsuitable(struct iter_env* iter_env, struct module_env* env,
- uint8_t* name, size_t namelen, uint16_t qtype, time_t now,
+ uint8_t* name, size_t namelen, uint16_t qtype, time_t now,
struct delegpt_addr* a)
{
int rtt, lame, reclame, dnsseclame;
@@ -243,8 +244,8 @@ iter_filter_unsuitable(struct iter_env* iter_env, struct module_env* env,
return -1; /* there is no ip4 available */
}
/* check lameness - need zone , class info */
- if(infra_get_lame_rtt(env->infra_cache, &a->addr, a->addrlen,
- name, namelen, qtype, &lame, &dnsseclame, &reclame,
+ if(infra_get_lame_rtt(env->infra_cache, &a->addr, a->addrlen,
+ name, namelen, qtype, &lame, &dnsseclame, &reclame,
&rtt, now)) {
log_addr(VERB_ALGO, "servselect", &a->addr, a->addrlen);
verbose(VERB_ALGO, " rtt=%d%s%s%s%s", rtt,
@@ -282,7 +283,7 @@ iter_filter_unsuitable(struct iter_env* iter_env, struct module_env* env,
/** lookup RTT information, and also store fastest rtt (if any) */
static int
iter_fill_rtt(struct iter_env* iter_env, struct module_env* env,
- uint8_t* name, size_t namelen, uint16_t qtype, time_t now,
+ uint8_t* name, size_t namelen, uint16_t qtype, time_t now,
struct delegpt* dp, int* best_rtt, struct sock_list* blacklist,
size_t* num_suitable_results)
{
@@ -293,7 +294,7 @@ iter_fill_rtt(struct iter_env* iter_env, struct module_env* env,
if(dp->bogus)
return 0; /* NS bogus, all bogus, nothing found */
for(a=dp->result_list; a; a = a->next_result) {
- a->sel_rtt = iter_filter_unsuitable(iter_env, env,
+ a->sel_rtt = iter_filter_unsuitable(iter_env, env,
name, namelen, qtype, now, a);
if(a->sel_rtt != -1) {
if(sock_list_find(blacklist, &a->addr, a->addrlen))
@@ -329,7 +330,7 @@ nth_rtt(struct delegpt_addr* result_list, size_t num_results, size_t n)
int rtt_band;
size_t i;
int* rtt_list, *rtt_index;
-
+
if(num_results < 1 || n >= num_results) {
return -1;
}
@@ -361,8 +362,8 @@ nth_rtt(struct delegpt_addr* result_list, size_t num_results, size_t n)
* returns number of best targets (or 0, no suitable targets) */
static int
iter_filter_order(struct iter_env* iter_env, struct module_env* env,
- uint8_t* name, size_t namelen, uint16_t qtype, time_t now,
- struct delegpt* dp, int* selected_rtt, int open_target,
+ uint8_t* name, size_t namelen, uint16_t qtype, time_t now,
+ struct delegpt* dp, int* selected_rtt, int open_target,
struct sock_list* blacklist, time_t prefetch)
{
int got_num = 0, low_rtt = 0, swap_to_front, rtt_band = RTT_BAND, nth;
@@ -370,9 +371,9 @@ iter_filter_order(struct iter_env* iter_env, struct module_env* env,
struct delegpt_addr* a, *n, *prev=NULL;
/* fillup sel_rtt and find best rtt in the bunch */
- got_num = iter_fill_rtt(iter_env, env, name, namelen, qtype, now, dp,
+ got_num = iter_fill_rtt(iter_env, env, name, namelen, qtype, now, dp,
&low_rtt, blacklist, &num_results);
- if(got_num == 0)
+ if(got_num == 0)
return 0;
if(low_rtt >= USEFUL_SERVER_TOP_TIMEOUT &&
(delegpt_count_missing_targets(dp) > 0 || open_target > 0)) {
@@ -548,9 +549,9 @@ iter_filter_order(struct iter_env* iter_env, struct module_env* env,
return got_num;
}
-struct delegpt_addr*
-iter_server_selection(struct iter_env* iter_env,
- struct module_env* env, struct delegpt* dp,
+struct delegpt_addr*
+iter_server_selection(struct iter_env* iter_env,
+ struct module_env* env, struct delegpt* dp,
uint8_t* name, size_t namelen, uint16_t qtype, int* dnssec_lame,
int* chase_to_rd, int open_target, struct sock_list* blacklist,
time_t prefetch)
@@ -592,7 +593,7 @@ iter_server_selection(struct iter_env* iter_env,
if(num == 1) {
a = dp->result_list;
- if(++a->attempts < OUTBOUND_MSG_RETRY)
+ if(++a->attempts < iter_env->outbound_msg_retry)
return a;
dp->result_list = a->next_result;
return a;
@@ -602,7 +603,7 @@ iter_server_selection(struct iter_env* iter_env,
log_assert(num > 1);
/* grab secure random number, to pick unexpected server.
* also we need it to be threadsafe. */
- sel = ub_random_max(env->rnd, num);
+ sel = ub_random_max(env->rnd, num);
a = dp->result_list;
prev = NULL;
while(sel > 0 && a) {
@@ -612,7 +613,7 @@ iter_server_selection(struct iter_env* iter_env,
}
if(!a) /* robustness */
return NULL;
- if(++a->attempts < OUTBOUND_MSG_RETRY)
+ if(++a->attempts < iter_env->outbound_msg_retry)
return a;
/* remove it from the delegation point result list */
if(prev)
@@ -621,8 +622,8 @@ iter_server_selection(struct iter_env* iter_env,
return a;
}
-struct dns_msg*
-dns_alloc_msg(sldns_buffer* pkt, struct msg_parse* msg,
+struct dns_msg*
+dns_alloc_msg(sldns_buffer* pkt, struct msg_parse* msg,
struct regional* region)
{
struct dns_msg* m = (struct dns_msg*)regional_alloc(region,
@@ -637,7 +638,7 @@ dns_alloc_msg(sldns_buffer* pkt, struct msg_parse* msg,
return m;
}
-struct dns_msg*
+struct dns_msg*
dns_copy_msg(struct dns_msg* from, struct regional* region)
{
struct dns_msg* m = (struct dns_msg*)regional_alloc(region,
@@ -653,7 +654,7 @@ dns_copy_msg(struct dns_msg* from, struct regional* region)
return m;
}
-void
+void
iter_dns_store(struct module_env* env, struct query_info* msgqinf,
struct reply_info* msgrep, int is_referral, time_t leeway, int pside,
struct regional* region, uint16_t flags)
@@ -663,7 +664,7 @@ iter_dns_store(struct module_env* env, struct query_info* msgqinf,
log_err("out of memory: cannot store data in cache");
}
-int
+int
iter_ns_probability(struct ub_randstate* rnd, int n, int m)
{
int sel;
@@ -671,7 +672,7 @@ iter_ns_probability(struct ub_randstate* rnd, int n, int m)
return 1;
/* we do not need secure random numbers here, but
* we do need it to be threadsafe, so we use this */
- sel = ub_random_max(rnd, m);
+ sel = ub_random_max(rnd, m);
return (sel < n);
}
@@ -688,12 +689,12 @@ causes_cycle(struct module_qstate* qstate, uint8_t* name, size_t namelen,
qinf.local_alias = NULL;
fptr_ok(fptr_whitelist_modenv_detect_cycle(
qstate->env->detect_cycle));
- return (*qstate->env->detect_cycle)(qstate, &qinf,
+ return (*qstate->env->detect_cycle)(qstate, &qinf,
(uint16_t)(BIT_RD|BIT_CD), qstate->is_priming,
qstate->is_valrec);
}
-void
+void
iter_mark_cycle_targets(struct module_qstate* qstate, struct delegpt* dp)
{
struct delegpt_ns* ns;
@@ -701,21 +702,21 @@ iter_mark_cycle_targets(struct module_qstate* qstate, struct delegpt* dp)
if(ns->resolved)
continue;
/* see if this ns as target causes dependency cycle */
- if(causes_cycle(qstate, ns->name, ns->namelen,
+ if(causes_cycle(qstate, ns->name, ns->namelen,
LDNS_RR_TYPE_AAAA, qstate->qinfo.qclass) ||
- causes_cycle(qstate, ns->name, ns->namelen,
+ causes_cycle(qstate, ns->name, ns->namelen,
LDNS_RR_TYPE_A, qstate->qinfo.qclass)) {
log_nametypeclass(VERB_QUERY, "skipping target due "
"to dependency cycle (harden-glue: no may "
- "fix some of the cycles)",
- ns->name, LDNS_RR_TYPE_A,
+ "fix some of the cycles)",
+ ns->name, LDNS_RR_TYPE_A,
qstate->qinfo.qclass);
ns->resolved = 1;
}
}
}
-void
+void
iter_mark_pside_cycle_targets(struct module_qstate* qstate, struct delegpt* dp)
{
struct delegpt_ns* ns;
@@ -723,14 +724,14 @@ iter_mark_pside_cycle_targets(struct module_qstate* qstate, struct delegpt* dp)
if(ns->done_pside4 && ns->done_pside6)
continue;
/* see if this ns as target causes dependency cycle */
- if(causes_cycle(qstate, ns->name, ns->namelen,
+ if(causes_cycle(qstate, ns->name, ns->namelen,
LDNS_RR_TYPE_A, qstate->qinfo.qclass)) {
log_nametypeclass(VERB_QUERY, "skipping target due "
"to dependency cycle", ns->name,
LDNS_RR_TYPE_A, qstate->qinfo.qclass);
ns->done_pside4 = 1;
}
- if(causes_cycle(qstate, ns->name, ns->namelen,
+ if(causes_cycle(qstate, ns->name, ns->namelen,
LDNS_RR_TYPE_AAAA, qstate->qinfo.qclass)) {
log_nametypeclass(VERB_QUERY, "skipping target due "
"to dependency cycle", ns->name,
@@ -740,8 +741,8 @@ iter_mark_pside_cycle_targets(struct module_qstate* qstate, struct delegpt* dp)
}
}
-int
-iter_dp_is_useless(struct query_info* qinfo, uint16_t qflags,
+int
+iter_dp_is_useless(struct query_info* qinfo, uint16_t qflags,
struct delegpt* dp)
{
struct delegpt_ns* ns;
@@ -760,14 +761,14 @@ iter_dp_is_useless(struct query_info* qinfo, uint16_t qflags,
/* either available or unused targets */
if(dp->usable_list || dp->result_list)
return 0;
-
+
/* see if query is for one of the nameservers, which is glue */
if( (qinfo->qtype == LDNS_RR_TYPE_A ||
qinfo->qtype == LDNS_RR_TYPE_AAAA) &&
dname_subdomain_c(qinfo->qname, dp->name) &&
delegpt_find_ns(dp, qinfo->qname, qinfo->qname_len))
return 1;
-
+
for(ns = dp->nslist; ns; ns = ns->next) {
if(ns->resolved) /* skip failed targets */
continue;
@@ -785,7 +786,7 @@ iter_qname_indicates_dnssec(struct module_env* env, struct query_info *qinfo)
return 0;
/* a trust anchor exists above the name? */
if((a=anchors_lookup(env->anchors, qinfo->qname, qinfo->qname_len,
- qinfo->qclass))) {
+ qinfo->qclass))) {
if(a->numDS == 0 && a->numDNSKEY == 0) {
/* insecure trust point */
lock_basic_unlock(&a->lock);
@@ -798,7 +799,7 @@ iter_qname_indicates_dnssec(struct module_env* env, struct query_info *qinfo)
return 0;
}
-int
+int
iter_indicates_dnssec(struct module_env* env, struct delegpt* dp,
struct dns_msg* msg, uint16_t dclass)
{
@@ -842,7 +843,7 @@ iter_indicates_dnssec(struct module_env* env, struct delegpt* dp,
return 0;
}
-int
+int
iter_msg_has_dnssec(struct dns_msg* msg)
{
size_t i;
@@ -875,7 +876,7 @@ int iter_msg_from_zone(struct dns_msg* msg, struct delegpt* dp,
* and referral to example.com. NS ... , then origin zone
* is .com. For a referral to sub.example.com. NS ... then
* we do not know, since example.com. may be in between. */
- for(i=0; i<msg->rep->an_numrrsets+msg->rep->ns_numrrsets;
+ for(i=0; i<msg->rep->an_numrrsets+msg->rep->ns_numrrsets;
i++) {
struct ub_packed_rrset_key* s = msg->rep->rrsets[i];
if(ntohs(s->rk.type) == LDNS_RR_TYPE_NS &&
@@ -890,7 +891,7 @@ int iter_msg_from_zone(struct dns_msg* msg, struct delegpt* dp,
return 0;
}
log_assert(type==RESPONSE_TYPE_ANSWER || type==RESPONSE_TYPE_CNAME);
- /* not a referral, and not lame delegation (upwards), so,
+ /* not a referral, and not lame delegation (upwards), so,
* any NS rrset must be from the zone itself */
if(reply_find_rrset_section_an(msg->rep, dp->name, dp->namelen,
LDNS_RR_TYPE_NS, dclass) ||
@@ -906,7 +907,7 @@ int iter_msg_from_zone(struct dns_msg* msg, struct delegpt* dp,
}
/**
- * check equality of two rrsets
+ * check equality of two rrsets
* @param k1: rrset
* @param k2: rrset
* @return true if equal
@@ -935,7 +936,7 @@ rrset_equal(struct ub_packed_rrset_key* k1, struct ub_packed_rrset_key* k2)
for(i=0; i<t; i++) {
if(d1->rr_len[i] != d2->rr_len[i] ||
/* no ttl check: d1->rr_ttl[i] != d2->rr_ttl[i] ||*/
- memcmp(d1->rr_data[i], d2->rr_data[i],
+ memcmp(d1->rr_data[i], d2->rr_data[i],
d1->rr_len[i]) != 0)
return 0;
}
@@ -966,7 +967,7 @@ rrset_canonical_sort_cmp(const void* x, const void* y)
return 0;
}
-int
+int
reply_equal(struct reply_info* p, struct reply_info* q, struct regional* region)
{
size_t i;
@@ -1024,7 +1025,7 @@ reply_equal(struct reply_info* p, struct reply_info* q, struct regional* region)
return 1;
}
-void
+void
caps_strip_reply(struct reply_info* rep)
{
size_t i;
@@ -1066,8 +1067,8 @@ int caps_failed_rcode(struct reply_info* rep)
FLAGS_GET_RCODE(rep->flags) == LDNS_RCODE_NXDOMAIN);
}
-void
-iter_store_parentside_rrset(struct module_env* env,
+void
+iter_store_parentside_rrset(struct module_env* env,
struct ub_packed_rrset_key* rrset)
{
struct rrset_ref ref;
@@ -1107,12 +1108,12 @@ iter_store_parentside_NS(struct module_env* env, struct reply_info* rep)
}
}
-void iter_store_parentside_neg(struct module_env* env,
+void iter_store_parentside_neg(struct module_env* env,
struct query_info* qinfo, struct reply_info* rep)
{
/* TTL: NS from referral in iq->deleg_msg,
* or first RR from iq->response,
- * or servfail5secs if !iq->response */
+ * or servfail5secs if !iq->response */
time_t ttl = NORR_TTL;
struct ub_packed_rrset_key* neg;
struct packed_rrset_data* newd;
@@ -1133,7 +1134,7 @@ void iter_store_parentside_neg(struct module_env* env,
neg->rk.type = htons(qinfo->qtype);
neg->rk.rrset_class = htons(qinfo->qclass);
neg->rk.flags = 0;
- neg->rk.dname = regional_alloc_init(env->scratch, qinfo->qname,
+ neg->rk.dname = regional_alloc_init(env->scratch, qinfo->qname,
qinfo->qname_len);
if(!neg->rk.dname) {
log_err("out of memory in store_parentside_neg");
@@ -1141,7 +1142,7 @@ void iter_store_parentside_neg(struct module_env* env,
}
neg->rk.dname_len = qinfo->qname_len;
neg->entry.hash = rrset_key_hash(&neg->rk);
- newd = (struct packed_rrset_data*)regional_alloc_zero(env->scratch,
+ newd = (struct packed_rrset_data*)regional_alloc_zero(env->scratch,
sizeof(struct packed_rrset_data) + sizeof(size_t) +
sizeof(uint8_t*) + sizeof(time_t) + sizeof(uint16_t));
if(!newd) {
@@ -1166,13 +1167,13 @@ void iter_store_parentside_neg(struct module_env* env,
iter_store_parentside_rrset(env, neg);
}
-int
+int
iter_lookup_parent_NS_from_cache(struct module_env* env, struct delegpt* dp,
struct regional* region, struct query_info* qinfo)
{
struct ub_packed_rrset_key* akey;
- akey = rrset_cache_lookup(env->rrset_cache, dp->name,
- dp->namelen, LDNS_RR_TYPE_NS, qinfo->qclass,
+ akey = rrset_cache_lookup(env->rrset_cache, dp->name,
+ dp->namelen, LDNS_RR_TYPE_NS, qinfo->qclass,
PACKED_RRSET_PARENT_SIDE, *env->now, 0);
if(akey) {
log_rrset_key(VERB_ALGO, "found parent-side NS in cache", akey);
@@ -1195,8 +1196,8 @@ int iter_lookup_parent_glue_from_cache(struct module_env* env,
size_t num = delegpt_count_targets(dp);
for(ns = dp->nslist; ns; ns = ns->next) {
/* get cached parentside A */
- akey = rrset_cache_lookup(env->rrset_cache, ns->name,
- ns->namelen, LDNS_RR_TYPE_A, qinfo->qclass,
+ akey = rrset_cache_lookup(env->rrset_cache, ns->name,
+ ns->namelen, LDNS_RR_TYPE_A, qinfo->qclass,
PACKED_RRSET_PARENT_SIDE, *env->now, 0);
if(akey) {
log_rrset_key(VERB_ALGO, "found parent-side", akey);
@@ -1207,8 +1208,8 @@ int iter_lookup_parent_glue_from_cache(struct module_env* env,
lock_rw_unlock(&akey->entry.lock);
}
/* get cached parentside AAAA */
- akey = rrset_cache_lookup(env->rrset_cache, ns->name,
- ns->namelen, LDNS_RR_TYPE_AAAA, qinfo->qclass,
+ akey = rrset_cache_lookup(env->rrset_cache, ns->name,
+ ns->namelen, LDNS_RR_TYPE_AAAA, qinfo->qclass,
PACKED_RRSET_PARENT_SIDE, *env->now, 0);
if(akey) {
log_rrset_key(VERB_ALGO, "found parent-side", akey);
@@ -1223,8 +1224,8 @@ int iter_lookup_parent_glue_from_cache(struct module_env* env,
return delegpt_count_targets(dp) != num;
}
-int
-iter_get_next_root(struct iter_hints* hints, struct iter_forwards* fwd,
+int
+iter_get_next_root(struct iter_hints* hints, struct iter_forwards* fwd,
uint16_t* c)
{
uint16_t c1 = *c, c2 = *c;
@@ -1246,7 +1247,7 @@ void
iter_scrub_ds(struct dns_msg* msg, struct ub_packed_rrset_key* ns, uint8_t* z)
{
/* Only the DS record for the delegation itself is expected.
- * We allow DS for everything between the bailiwick and the
+ * We allow DS for everything between the bailiwick and the
* zonecut, thus DS records must be at or above the zonecut.
* And the DS records must be below the server authority zone.
* The answer section is already scrubbed. */
@@ -1260,7 +1261,7 @@ iter_scrub_ds(struct dns_msg* msg, struct ub_packed_rrset_key* ns, uint8_t* z)
s->rk.dname, ntohs(s->rk.type),
ntohs(s->rk.rrset_class));
memmove(msg->rep->rrsets+i, msg->rep->rrsets+i+1,
- sizeof(struct ub_packed_rrset_key*) *
+ sizeof(struct ub_packed_rrset_key*) *
(msg->rep->rrset_count-i-1));
msg->rep->ns_numrrsets--;
msg->rep->rrset_count--;
@@ -1284,11 +1285,11 @@ iter_scrub_nxdomain(struct dns_msg* msg)
msg->rep->an_numrrsets = 0;
}
-void iter_dec_attempts(struct delegpt* dp, int d)
+void iter_dec_attempts(struct delegpt* dp, int d, int outbound_msg_retry)
{
struct delegpt_addr* a;
for(a=dp->target_list; a; a = a->next_target) {
- if(a->attempts >= OUTBOUND_MSG_RETRY) {
+ if(a->attempts >= outbound_msg_retry) {
/* add back to result list */
a->next_result = dp->result_list;
dp->result_list = a;
@@ -1299,7 +1300,8 @@ void iter_dec_attempts(struct delegpt* dp, int d)
}
}
-void iter_merge_retry_counts(struct delegpt* dp, struct delegpt* old)
+void iter_merge_retry_counts(struct delegpt* dp, struct delegpt* old,
+ int outbound_msg_retry)
{
struct delegpt_addr* a, *o, *prev;
for(a=dp->target_list; a; a = a->next_target) {
@@ -1313,7 +1315,7 @@ void iter_merge_retry_counts(struct delegpt* dp, struct delegpt* old)
prev = NULL;
a = dp->usable_list;
while(a) {
- if(a->attempts >= OUTBOUND_MSG_RETRY) {
+ if(a->attempts >= outbound_msg_retry) {
log_addr(VERB_ALGO, "remove from usable list dp",
&a->addr, a->addrlen);
/* remove from result list */
diff --git a/contrib/unbound/iterator/iter_utils.h b/contrib/unbound/iterator/iter_utils.h
index 509d2921e306..0a40916c0e02 100644
--- a/contrib/unbound/iterator/iter_utils.h
+++ b/contrib/unbound/iterator/iter_utils.h
@@ -347,16 +347,19 @@ void iter_scrub_nxdomain(struct dns_msg* msg);
* Remove query attempts from all available ips. For 0x20.
* @param dp: delegpt.
* @param d: decrease.
+ * @param outbound_msg_retry: number of retries of outgoing queries
*/
-void iter_dec_attempts(struct delegpt* dp, int d);
+void iter_dec_attempts(struct delegpt* dp, int d, int outbound_msg_retry);
/**
* Add retry counts from older delegpt to newer delegpt.
* Does not waste time on timeout'd (or other failing) addresses.
* @param dp: new delegationpoint.
* @param old: old delegationpoint.
+ * @param outbound_msg_retry: number of retries of outgoing queries
*/
-void iter_merge_retry_counts(struct delegpt* dp, struct delegpt* old);
+void iter_merge_retry_counts(struct delegpt* dp, struct delegpt* old,
+ int outbound_msg_retry);
/**
* See if a DS response (type ANSWER) is too low: a nodata answer with
diff --git a/contrib/unbound/iterator/iterator.c b/contrib/unbound/iterator/iterator.c
index f0105ad4b085..48238a231b13 100644
--- a/contrib/unbound/iterator/iterator.c
+++ b/contrib/unbound/iterator/iterator.c
@@ -2298,7 +2298,7 @@ processQueryTargets(struct module_qstate* qstate, struct iter_qstate* iq,
iq->minimise_count++;
iq->timeout_count = 0;
- iter_dec_attempts(iq->dp, 1);
+ iter_dec_attempts(iq->dp, 1, ie->outbound_msg_retry);
/* Limit number of iterations for QNAMEs with more
* than MAX_MINIMISE_COUNT labels. Send first MINIMISE_ONE_LAB
@@ -2500,7 +2500,7 @@ processQueryTargets(struct module_qstate* qstate, struct iter_qstate* iq,
(int)iq->caps_server+1, (int)naddr*3);
iq->response = iq->caps_response;
iq->caps_fallback = 0;
- iter_dec_attempts(iq->dp, 3); /* space for fallback */
+ iter_dec_attempts(iq->dp, 3, ie->outbound_msg_retry); /* space for fallback */
iq->num_current_queries++; /* RespState decrements it*/
iq->referral_count++; /* make sure we don't loop */
iq->sent_count = 0;
@@ -2529,6 +2529,23 @@ processQueryTargets(struct module_qstate* qstate, struct iter_qstate* iq,
/* Add the current set of unused targets to our queue. */
delegpt_add_unused_targets(iq->dp);
+ if(qstate->env->auth_zones) {
+ /* apply rpz triggers at query time */
+ struct dns_msg* forged_response = rpz_callback_from_iterator_module(qstate, iq);
+ if(forged_response != NULL) {
+ qstate->ext_state[id] = module_finished;
+ qstate->return_rcode = FLAGS_GET_RCODE(forged_response->rep->flags);
+ qstate->return_msg = forged_response;
+ iq->response = forged_response;
+ next_state(iq, FINISHED_STATE);
+ if(!iter_prepend(iq, qstate->return_msg, qstate->region)) {
+ log_err("rpz, prepend rrsets: out of memory");
+ return error_response(qstate, id, LDNS_RCODE_SERVFAIL);
+ }
+ return 0;
+ }
+ }
+
/* Select the next usable target, filtering out unsuitable targets. */
target = iter_server_selection(ie, qstate->env, iq->dp,
iq->dp->name, iq->dp->namelen, iq->qchase.qtype,
@@ -2588,7 +2605,7 @@ processQueryTargets(struct module_qstate* qstate, struct iter_qstate* iq,
(int)iq->caps_server+1);
iq->response = iq->caps_response;
iq->caps_fallback = 0;
- iter_dec_attempts(iq->dp, 3); /* space for fallback */
+ iter_dec_attempts(iq->dp, 3, ie->outbound_msg_retry); /* space for fallback */
iq->num_current_queries++; /* RespState decrements it*/
iq->referral_count++; /* make sure we don't loop */
iq->sent_count = 0;
@@ -2666,6 +2683,7 @@ processQueryTargets(struct module_qstate* qstate, struct iter_qstate* iq,
iq->dnssec_expected, iq->caps_fallback || is_caps_whitelisted(
ie, iq), &target->addr, target->addrlen,
iq->dp->name, iq->dp->namelen,
+ (iq->dp->tcp_upstream || qstate->env->cfg->tcp_upstream),
(iq->dp->ssl_upstream || qstate->env->cfg->ssl_upstream),
target->tls_auth_name, qstate);
if(!outq) {
@@ -2707,6 +2725,7 @@ find_NS(struct reply_info* rep, size_t from, size_t to)
*
* @param qstate: query state.
* @param iq: iterator query state.
+ * @param ie: iterator shared global environment.
* @param id: module id.
* @return true if the event requires more immediate processing, false if
* not. This is generally only true when forwarding the request to
@@ -2714,10 +2733,11 @@ find_NS(struct reply_info* rep, size_t from, size_t to)
*/
static int
processQueryResponse(struct module_qstate* qstate, struct iter_qstate* iq,
- int id)
+ struct iter_env* ie, int id)
{
int dnsseclame = 0;
enum response_type type;
+
iq->num_current_queries--;
if(!inplace_cb_query_response_call(qstate->env, qstate, iq->response))
@@ -2983,7 +3003,8 @@ processQueryResponse(struct module_qstate* qstate, struct iter_qstate* iq,
}
if(iq->store_parent_NS && query_dname_compare(iq->dp->name,
iq->store_parent_NS->name) == 0)
- iter_merge_retry_counts(iq->dp, iq->store_parent_NS);
+ iter_merge_retry_counts(iq->dp, iq->store_parent_NS,
+ ie->outbound_msg_retry);
delegpt_log(VERB_ALGO, iq->dp);
/* Count this as a referral. */
iq->referral_count++;
@@ -3061,6 +3082,39 @@ processQueryResponse(struct module_qstate* qstate, struct iter_qstate* iq,
/* set the current request's qname to the new value. */
iq->qchase.qname = sname;
iq->qchase.qname_len = snamelen;
+ if(qstate->env->auth_zones) {
+ /* apply rpz qname triggers after cname */
+ struct dns_msg* forged_response =
+ rpz_callback_from_iterator_cname(qstate, iq);
+ while(forged_response && reply_find_rrset_section_an(
+ forged_response->rep, iq->qchase.qname,
+ iq->qchase.qname_len, LDNS_RR_TYPE_CNAME,
+ iq->qchase.qclass)) {
+ /* another cname to follow */
+ if(!handle_cname_response(qstate, iq, forged_response,
+ &sname, &snamelen)) {
+ errinf(qstate, "malloc failure, CNAME info");
+ return error_response(qstate, id, LDNS_RCODE_SERVFAIL);
+ }
+ iq->qchase.qname = sname;
+ iq->qchase.qname_len = snamelen;
+ forged_response =
+ rpz_callback_from_iterator_cname(qstate, iq);
+ }
+ if(forged_response != NULL) {
+ qstate->ext_state[id] = module_finished;
+ qstate->return_rcode = FLAGS_GET_RCODE(forged_response->rep->flags);
+ qstate->return_msg = forged_response;
+ iq->response = forged_response;
+ next_state(iq, FINISHED_STATE);
+ if(!iter_prepend(iq, qstate->return_msg, qstate->region)) {
+ log_err("rpz after cname, prepend rrsets: out of memory");
+ return error_response(qstate, id, LDNS_RCODE_SERVFAIL);
+ }
+ qstate->return_msg->qinfo = qstate->qinfo;
+ return 0;
+ }
+ }
/* Clear the query state, since this is a query restart. */
iq->deleg_msg = NULL;
iq->dp = NULL;
@@ -3188,7 +3242,7 @@ prime_supers(struct module_qstate* qstate, int id, struct module_qstate* forq)
/* Convert our response to a delegation point */
dp = delegpt_from_message(qstate->return_msg, forq->region);
if(!dp) {
- /* if there is no convertable delegation point, then
+ /* if there is no convertible delegation point, then
* the ANSWER type was (presumably) a negative answer. */
verbose(VERB_ALGO, "prime response was not a positive "
"ANSWER; failing");
@@ -3694,7 +3748,7 @@ iter_handle(struct module_qstate* qstate, struct iter_qstate* iq,
cont = processQueryTargets(qstate, iq, ie, id);
break;
case QUERY_RESP_STATE:
- cont = processQueryResponse(qstate, iq, id);
+ cont = processQueryResponse(qstate, iq, ie, id);
break;
case PRIME_RESP_STATE:
cont = processPrimeResponse(qstate, id);
@@ -3764,7 +3818,7 @@ process_response(struct module_qstate* qstate, struct iter_qstate* iq,
iq->num_current_queries--;
/* need fresh attempts for the 0x20 fallback, if
* that was the cause for the failure */
- iter_dec_attempts(iq->dp, 3);
+ iter_dec_attempts(iq->dp, 3, ie->outbound_msg_retry);
verbose(VERB_DETAIL, "Capsforid: timeouts, starting fallback");
goto handle_it;
}
@@ -3798,15 +3852,15 @@ process_response(struct module_qstate* qstate, struct iter_qstate* iq,
goto handle_it;
}
/* edns is not examined, but removed from message to help cache */
- if(parse_extract_edns(prs, &edns, qstate->env->scratch) !=
+ if(parse_extract_edns_from_response_msg(prs, &edns, qstate->env->scratch) !=
LDNS_RCODE_NOERROR) {
iq->parse_failures++;
goto handle_it;
}
/* Copy the edns options we may got from the back end */
- if(edns.opt_list) {
- qstate->edns_opts_back_in = edns_opt_copy_region(edns.opt_list,
+ if(edns.opt_list_in) {
+ qstate->edns_opts_back_in = edns_opt_copy_region(edns.opt_list_in,
qstate->region);
if(!qstate->edns_opts_back_in) {
log_err("out of memory on incoming message");
diff --git a/contrib/unbound/iterator/iterator.h b/contrib/unbound/iterator/iterator.h
index dc5e57527d87..a9e58569fcf3 100644
--- a/contrib/unbound/iterator/iterator.h
+++ b/contrib/unbound/iterator/iterator.h
@@ -94,8 +94,6 @@ extern int UNKNOWN_SERVER_NICENESS;
* Equals RTT_MAX_TIMEOUT
*/
#define USEFUL_SERVER_TOP_TIMEOUT 120000
-/** number of retries on outgoing queries */
-#define OUTBOUND_MSG_RETRY 5
/** RTT band, within this amount from the best, servers are chosen randomly.
* Chosen so that the UNKNOWN_SERVER_NICENESS falls within the band of a
* fast server, this causes server exploration as a side benefit. msec. */
@@ -139,6 +137,9 @@ struct iter_env {
lock_basic_type queries_ratelimit_lock;
/** number of queries that have been ratelimited */
size_t num_queries_ratelimited;
+
+ /** number of retries on outgoing queries */
+ int outbound_msg_retry;
};
/**
diff --git a/contrib/unbound/libunbound/context.c b/contrib/unbound/libunbound/context.c
index e589c6ae28d7..c8d911f13c7f 100644
--- a/contrib/unbound/libunbound/context.c
+++ b/contrib/unbound/libunbound/context.c
@@ -48,6 +48,7 @@
#include "services/cache/rrset.h"
#include "services/cache/infra.h"
#include "services/authzone.h"
+#include "services/listen_dnsport.h"
#include "util/data/msgreply.h"
#include "util/storage/slabhash.h"
#include "util/edns.h"
@@ -73,6 +74,7 @@ context_finalize(struct ub_ctx* ctx)
config_apply(cfg);
if(!modstack_setup(&ctx->mods, cfg->module_conf, ctx->env))
return UB_INITFAIL;
+ listen_setup_locks();
log_edns_known_options(VERB_ALGO, ctx->env);
ctx->local_zones = local_zones_create();
if(!ctx->local_zones)
diff --git a/contrib/unbound/libunbound/context.h b/contrib/unbound/libunbound/context.h
index 78f8731e236e..c0c86fb52697 100644
--- a/contrib/unbound/libunbound/context.h
+++ b/contrib/unbound/libunbound/context.h
@@ -177,35 +177,6 @@ struct ctx_query {
};
/**
- * The error constants
- */
-enum ub_ctx_err {
- /** no error */
- UB_NOERROR = 0,
- /** socket operation. Set to -1, so that if an error from _fd() is
- * passed (-1) it gives a socket error. */
- UB_SOCKET = -1,
- /** alloc failure */
- UB_NOMEM = -2,
- /** syntax error */
- UB_SYNTAX = -3,
- /** DNS service failed */
- UB_SERVFAIL = -4,
- /** fork() failed */
- UB_FORKFAIL = -5,
- /** cfg change after finalize() */
- UB_AFTERFINAL = -6,
- /** initialization failed (bad settings) */
- UB_INITFAIL = -7,
- /** error in pipe communication with async bg worker */
- UB_PIPE = -8,
- /** error reading from file (resolv.conf) */
- UB_READFILE = -9,
- /** error async_id does not exist or result already been delivered */
- UB_NOID = -10
-};
-
-/**
* Command codes for libunbound pipe.
*
* Serialization looks like this:
diff --git a/contrib/unbound/libunbound/libunbound.c b/contrib/unbound/libunbound/libunbound.c
index c9e24ba8d8f2..038b7b927a74 100644
--- a/contrib/unbound/libunbound/libunbound.c
+++ b/contrib/unbound/libunbound/libunbound.c
@@ -64,6 +64,7 @@
#include "services/cache/infra.h"
#include "services/cache/rrset.h"
#include "services/authzone.h"
+#include "services/listen_dnsport.h"
#include "sldns/sbuffer.h"
#ifdef HAVE_PTHREAD
#include <signal.h>
@@ -185,6 +186,7 @@ ub_ctx_create(void)
ub_randfree(ctx->seed_rnd);
config_delete(ctx->env->cfg);
modstack_desetup(&ctx->mods, ctx->env);
+ listen_desetup_locks();
edns_known_options_delete(ctx->env);
edns_strings_delete(ctx->env->edns_strings);
free(ctx->env);
@@ -198,6 +200,7 @@ ub_ctx_create(void)
ub_randfree(ctx->seed_rnd);
config_delete(ctx->env->cfg);
modstack_desetup(&ctx->mods, ctx->env);
+ listen_desetup_locks();
edns_known_options_delete(ctx->env);
edns_strings_delete(ctx->env->edns_strings);
free(ctx->env);
@@ -344,6 +347,7 @@ ub_ctx_delete(struct ub_ctx* ctx)
}
ub_randfree(ctx->seed_rnd);
alloc_clear(&ctx->superalloc);
+ listen_desetup_locks();
traverse_postorder(&ctx->queries, delq, NULL);
if(ctx_logfile_overridden) {
log_file(NULL);
diff --git a/contrib/unbound/libunbound/libworker.c b/contrib/unbound/libunbound/libworker.c
index 8a9ca9419480..7f753435d068 100644
--- a/contrib/unbound/libunbound/libworker.c
+++ b/contrib/unbound/libunbound/libworker.c
@@ -600,7 +600,9 @@ setup_qinfo_edns(struct libworker* w, struct ctx_query* q,
edns->ext_rcode = 0;
edns->edns_version = 0;
edns->bits = EDNS_DO;
- edns->opt_list = NULL;
+ edns->opt_list_in = NULL;
+ edns->opt_list_out = NULL;
+ edns->opt_list_inplace_cb_out = NULL;
edns->padding_block_size = 0;
if(sldns_buffer_capacity(w->back->udp_buff) < 65535)
edns->udp_size = (uint16_t)sldns_buffer_capacity(
@@ -881,7 +883,7 @@ void libworker_alloc_cleanup(void* arg)
struct outbound_entry* libworker_send_query(struct query_info* qinfo,
uint16_t flags, int dnssec, int want_dnssec, int nocaps,
struct sockaddr_storage* addr, socklen_t addrlen, uint8_t* zone,
- size_t zonelen, int ssl_upstream, char* tls_auth_name,
+ size_t zonelen, int tcp_upstream, int ssl_upstream, char* tls_auth_name,
struct module_qstate* q)
{
struct libworker* w = (struct libworker*)q->env->worker;
@@ -891,7 +893,7 @@ struct outbound_entry* libworker_send_query(struct query_info* qinfo,
return NULL;
e->qstate = q;
e->qsent = outnet_serviced_query(w->back, qinfo, flags, dnssec,
- want_dnssec, nocaps, q->env->cfg->tcp_upstream, ssl_upstream,
+ want_dnssec, nocaps, tcp_upstream, ssl_upstream,
tls_auth_name, addr, addrlen, zone, zonelen, q,
libworker_handle_service_reply, e, w->back->udp_buff, q->env);
if(!e->qsent) {
@@ -975,7 +977,7 @@ struct outbound_entry* worker_send_query(struct query_info* ATTR_UNUSED(qinfo),
uint16_t ATTR_UNUSED(flags), int ATTR_UNUSED(dnssec),
int ATTR_UNUSED(want_dnssec), int ATTR_UNUSED(nocaps),
struct sockaddr_storage* ATTR_UNUSED(addr), socklen_t ATTR_UNUSED(addrlen),
- uint8_t* ATTR_UNUSED(zone), size_t ATTR_UNUSED(zonelen),
+ uint8_t* ATTR_UNUSED(zone), size_t ATTR_UNUSED(zonelen), int ATTR_UNUSED(tcp_upstream),
int ATTR_UNUSED(ssl_upstream), char* ATTR_UNUSED(tls_auth_name),
struct module_qstate* ATTR_UNUSED(q))
{
diff --git a/contrib/unbound/libunbound/unbound-event.h b/contrib/unbound/libunbound/unbound-event.h
index 4d694b8b4c5d..a5d5c038b68f 100644
--- a/contrib/unbound/libunbound/unbound-event.h
+++ b/contrib/unbound/libunbound/unbound-event.h
@@ -41,7 +41,7 @@
*
* Use ub_ctx_create_event_ub_base() to create an unbound context that uses
* the user provided event base API. Then, use the ub_resolve_event call
- * to add DNS resolve queries to the context. Those then run whith the
+ * to add DNS resolve queries to the context. Those then run with the
* provided event_base, and when they are done you get a function callback.
*
* This method does not fork another process or create a thread, the effort
diff --git a/contrib/unbound/libunbound/unbound.h b/contrib/unbound/libunbound/unbound.h
index 945c17a8fb5b..ee8558759065 100644
--- a/contrib/unbound/libunbound/unbound.h
+++ b/contrib/unbound/libunbound/unbound.h
@@ -224,7 +224,7 @@ struct ub_result {
* It is called with
* void* my_arg: your pointer to a (struct of) data of your choice,
* or NULL.
- * int err: if 0 all is OK, otherwise an error occured and no results
+ * int err: if 0 all is OK, otherwise an error occurred and no results
* are forthcoming.
* struct result: pointer to more detailed result structure.
* This structure is allocated on the heap and needs to be
@@ -233,6 +233,35 @@ struct ub_result {
typedef void (*ub_callback_type)(void*, int, struct ub_result*);
/**
+ * The error constants
+ */
+enum ub_ctx_err {
+ /** no error */
+ UB_NOERROR = 0,
+ /** socket operation. Set to -1, so that if an error from _fd() is
+ * passed (-1) it gives a socket error. */
+ UB_SOCKET = -1,
+ /** alloc failure */
+ UB_NOMEM = -2,
+ /** syntax error */
+ UB_SYNTAX = -3,
+ /** DNS service failed */
+ UB_SERVFAIL = -4,
+ /** fork() failed */
+ UB_FORKFAIL = -5,
+ /** cfg change after finalize() */
+ UB_AFTERFINAL = -6,
+ /** initialization failed (bad settings) */
+ UB_INITFAIL = -7,
+ /** error in pipe communication with async bg worker */
+ UB_PIPE = -8,
+ /** error reading from file (resolv.conf) */
+ UB_READFILE = -9,
+ /** error async_id does not exist or result already been delivered */
+ UB_NOID = -10
+};
+
+/**
* Create a resolving and validation context.
* The information from /etc/resolv.conf and /etc/hosts is not utilised by
* default. Use ub_ctx_resolvconf and ub_ctx_hosts to read them.
@@ -563,6 +592,7 @@ void ub_resolve_free(struct ub_result* result);
/**
* Convert error value to a human readable string.
* @param err: error code from one of the libunbound functions.
+ * The error codes are from the type enum ub_ctx_err.
* @return pointer to constant text string, zero terminated.
*/
const char* ub_strerror(int err);
diff --git a/contrib/unbound/libunbound/worker.h b/contrib/unbound/libunbound/worker.h
index bf7473861af8..974b66a30e84 100644
--- a/contrib/unbound/libunbound/worker.h
+++ b/contrib/unbound/libunbound/worker.h
@@ -62,17 +62,18 @@ struct query_info;
* @param addrlen: length of addr.
* @param zone: delegation point name.
* @param zonelen: length of zone name wireformat dname.
+ * @param tcp_upstream: use TCP for upstream queries.
* @param ssl_upstream: use SSL for upstream queries.
* @param tls_auth_name: if ssl_upstream, use this name with TLS
* authentication.
- * @param q: wich query state to reactivate upon return.
+ * @param q: which query state to reactivate upon return.
* @return: false on failure (memory or socket related). no query was
* sent.
*/
struct outbound_entry* libworker_send_query(struct query_info* qinfo,
uint16_t flags, int dnssec, int want_dnssec, int nocaps,
struct sockaddr_storage* addr, socklen_t addrlen, uint8_t* zone,
- size_t zonelen, int ssl_upstream, char* tls_auth_name,
+ size_t zonelen, int tcp_upstream, int ssl_upstream, char* tls_auth_name,
struct module_qstate* q);
/** process incoming serviced query replies from the network */
@@ -113,17 +114,18 @@ void worker_sighandler(int sig, void* arg);
* @param addrlen: length of addr.
* @param zone: wireformat dname of the zone.
* @param zonelen: length of zone name.
+ * @param tcp_upstream: use TCP for upstream queries.
* @param ssl_upstream: use SSL for upstream queries.
* @param tls_auth_name: if ssl_upstream, use this name with TLS
* authentication.
- * @param q: wich query state to reactivate upon return.
+ * @param q: which query state to reactivate upon return.
* @return: false on failure (memory or socket related). no query was
* sent.
*/
struct outbound_entry* worker_send_query(struct query_info* qinfo,
uint16_t flags, int dnssec, int want_dnssec, int nocaps,
struct sockaddr_storage* addr, socklen_t addrlen, uint8_t* zone,
- size_t zonelen, int ssl_upstream, char* tls_auth_name,
+ size_t zonelen, int tcp_upstream, int ssl_upstream, char* tls_auth_name,
struct module_qstate* q);
/**
diff --git a/contrib/unbound/respip/respip.c b/contrib/unbound/respip/respip.c
index aae41f5d6368..3d1b3feaf460 100644
--- a/contrib/unbound/respip/respip.c
+++ b/contrib/unbound/respip/respip.c
@@ -25,6 +25,7 @@
#include "respip/respip.h"
#include "services/view.h"
#include "sldns/rrdef.h"
+#include "util/data/dname.h"
/** Subset of resp_addr.node, used for inform-variant logging */
@@ -483,8 +484,8 @@ respip_views_apply_cfg(struct views* vs, struct config_file* cfg,
* This function returns the copied rrset key on success, and NULL on memory
* allocation failure.
*/
-static struct ub_packed_rrset_key*
-copy_rrset(const struct ub_packed_rrset_key* key, struct regional* region)
+struct ub_packed_rrset_key*
+respip_copy_rrset(const struct ub_packed_rrset_key* key, struct regional* region)
{
struct ub_packed_rrset_key* ck = regional_alloc(region,
sizeof(struct ub_packed_rrset_key));
@@ -602,7 +603,7 @@ rdata2sockaddr(const struct packed_rrset_data* rd, uint16_t rtype, size_t i,
*/
static struct resp_addr*
respip_addr_lookup(const struct reply_info *rep, struct respip_set* rs,
- size_t* rrset_id)
+ size_t* rrset_id, size_t* rr_id)
{
size_t i;
struct resp_addr* ra;
@@ -625,6 +626,7 @@ respip_addr_lookup(const struct reply_info *rep, struct respip_set* rs,
&ss, addrlen);
if(ra) {
*rrset_id = i;
+ *rr_id = j;
lock_rw_rdlock(&ra->lock);
lock_rw_unlock(&rs->lock);
return ra;
@@ -635,43 +637,6 @@ respip_addr_lookup(const struct reply_info *rep, struct respip_set* rs,
return NULL;
}
-/*
- * Create a new reply_info based on 'rep'. The new info is based on
- * the passed 'rep', but ignores any rrsets except for the first 'an_numrrsets'
- * RRsets in the answer section. These answer rrsets are copied to the
- * new info, up to 'copy_rrsets' rrsets (which must not be larger than
- * 'an_numrrsets'). If an_numrrsets > copy_rrsets, the remaining rrsets array
- * entries will be kept empty so the caller can fill them later. When rrsets
- * are copied, they are shallow copied. The caller must ensure that the
- * copied rrsets are valid throughout its lifetime and must provide appropriate
- * mutex if it can be shared by multiple threads.
- */
-static struct reply_info *
-make_new_reply_info(const struct reply_info* rep, struct regional* region,
- size_t an_numrrsets, size_t copy_rrsets)
-{
- struct reply_info* new_rep;
- size_t i;
-
- /* create a base struct. we specify 'insecure' security status as
- * the modified response won't be DNSSEC-valid. In our faked response
- * the authority and additional sections will be empty (except possible
- * EDNS0 OPT RR in the additional section appended on sending it out),
- * so the total number of RRsets is an_numrrsets. */
- new_rep = construct_reply_info_base(region, rep->flags,
- rep->qdcount, rep->ttl, rep->prefetch_ttl,
- rep->serve_expired_ttl, an_numrrsets, 0, 0, an_numrrsets,
- sec_status_insecure);
- if(!new_rep)
- return NULL;
- if(!reply_info_alloc_rrset_keys(new_rep, NULL, region))
- return NULL;
- for(i=0; i<copy_rrsets; i++)
- new_rep->rrsets[i] = rep->rrsets[i];
-
- return new_rep;
-}
-
/**
* See if response-ip or tag data should override the original answer rrset
* (which is rep->rrsets[rrset_id]) and if so override it.
@@ -730,7 +695,7 @@ respip_data_answer(enum respip_action action,
"response-ip redirect with tag data [%d] %s",
tag, (tag<num_tags?tagname[tag]:"null"));
/* use copy_rrset() to 'normalize' memory layout */
- rp = copy_rrset(&r, region);
+ rp = respip_copy_rrset(&r, region);
if(!rp)
return -1;
}
@@ -743,7 +708,7 @@ respip_data_answer(enum respip_action action,
* rename the dname for other actions than redirect. This is because
* response-ip-data isn't associated to any specific name. */
if(rp == data) {
- rp = copy_rrset(rp, region);
+ rp = respip_copy_rrset(rp, region);
if(!rp)
return -1;
rp->rk.dname = rep->rrsets[rrset_id]->rk.dname;
@@ -807,7 +772,6 @@ respip_nodata_answer(uint16_t qtype, enum respip_action action,
* is explicitly specified. */
int rcode = (action == respip_always_nxdomain)?
LDNS_RCODE_NXDOMAIN:LDNS_RCODE_NOERROR;
-
/* We should empty the answer section except for any preceding
* CNAMEs (in that case rrset_id > 0). Type-ANY case is
* special as noted in respip_data_answer(). */
@@ -907,7 +871,7 @@ respip_rewrite_reply(const struct query_info* qinfo,
size_t tag_datas_size;
struct view* view = NULL;
struct respip_set* ipset = NULL;
- size_t rrset_id = 0;
+ size_t rrset_id = 0, rr_id = 0;
enum respip_action action = respip_none;
int tag = -1;
struct resp_addr* raddr = NULL;
@@ -948,7 +912,7 @@ respip_rewrite_reply(const struct query_info* qinfo,
lock_rw_rdlock(&view->lock);
if(view->respip_set) {
if((raddr = respip_addr_lookup(rep,
- view->respip_set, &rrset_id))) {
+ view->respip_set, &rrset_id, &rr_id))) {
/** for per-view respip directives the action
* can only be direct (i.e. not tag-based) */
action = raddr->action;
@@ -962,7 +926,7 @@ respip_rewrite_reply(const struct query_info* qinfo,
}
}
if(!raddr && (raddr = respip_addr_lookup(rep, ipset,
- &rrset_id))) {
+ &rrset_id, &rr_id))) {
action = (enum respip_action)local_data_find_tag_action(
raddr->taglist, raddr->taglen, ctaglist, ctaglen,
tag_actions, tag_actions_size,
@@ -976,7 +940,7 @@ respip_rewrite_reply(const struct query_info* qinfo,
if(!r->taglist || taglist_intersect(r->taglist,
r->taglistlen, ctaglist, ctaglen)) {
if((raddr = respip_addr_lookup(rep,
- r->respip_set, &rrset_id))) {
+ r->respip_set, &rrset_id, &rr_id))) {
if(!respip_use_rpz(raddr, r, &action, &data,
&rpz_log, &log_name, &rpz_cname_override,
region, &rpz_used)) {
@@ -987,6 +951,21 @@ respip_rewrite_reply(const struct query_info* qinfo,
return 0;
}
if(rpz_used) {
+ if(verbosity >= VERB_ALGO) {
+ struct sockaddr_storage ss;
+ socklen_t ss_len = 0;
+ char nm[256], ip[256];
+ char qn[255+1];
+ if(!rdata2sockaddr(rep->rrsets[rrset_id]->entry.data, ntohs(rep->rrsets[rrset_id]->rk.type), rr_id, &ss, &ss_len))
+ snprintf(ip, sizeof(ip), "invalidRRdata");
+ else
+ addr_to_str(&ss, ss_len, ip, sizeof(ip));
+ dname_str(qinfo->qname, qn);
+ addr_to_str(&raddr->node.addr,
+ raddr->node.addrlen,
+ nm, sizeof(nm));
+ verbose(VERB_ALGO, "respip: rpz response-ip trigger %s/%d on %s %s with action %s", nm, raddr->node.net, qn, ip, rpz_action_to_string(respip_action_to_rpz_action(action)));
+ }
/* break to make sure 'a' stays pointed
* to used auth_zone, and keeps lock */
break;
@@ -1209,7 +1188,7 @@ respip_merge_cname(struct reply_info* base_rep,
if(!new_rep)
return 0;
for(i=0,j=base_rep->an_numrrsets; i<tgt_rep->an_numrrsets; i++,j++) {
- new_rep->rrsets[j] = copy_rrset(tgt_rep->rrsets[i], region);
+ new_rep->rrsets[j] = respip_copy_rrset(tgt_rep->rrsets[i], region);
if(!new_rep->rrsets[j])
return 0;
}
diff --git a/contrib/unbound/respip/respip.h b/contrib/unbound/respip/respip.h
index bbd471421c1e..3dfb4e9f01c7 100644
--- a/contrib/unbound/respip/respip.h
+++ b/contrib/unbound/respip/respip.h
@@ -294,4 +294,7 @@ respip_enter_rr(struct regional* region, struct resp_addr* raddr,
*/
void
respip_sockaddr_delete(struct respip_set* set, struct resp_addr* node);
+
+struct ub_packed_rrset_key*
+respip_copy_rrset(const struct ub_packed_rrset_key* key, struct regional* region);
#endif /* RESPIP_RESPIP_H */
diff --git a/contrib/unbound/services/authzone.c b/contrib/unbound/services/authzone.c
index d56f74a0ab3c..4598a8286510 100644
--- a/contrib/unbound/services/authzone.c
+++ b/contrib/unbound/services/authzone.c
@@ -84,7 +84,7 @@
#define AUTH_PROBE_TIMEOUT_STOP 1000 /* msec */
/* auth transfer timeout for TCP connections, in msec */
#define AUTH_TRANSFER_TIMEOUT 10000 /* msec */
-/* auth transfer max backoff for failed tranfers and probes */
+/* auth transfer max backoff for failed transfers and probes */
#define AUTH_TRANSFER_MAX_BACKOFF 86400 /* sec */
/* auth http port number */
#define AUTH_HTTP_PORT 80
@@ -243,7 +243,7 @@ msg_add_rrset_an(struct auth_zone* z, struct regional* region,
return 1;
}
-/** add rrset to authority section (no additonal section rrsets yet) */
+/** add rrset to authority section (no additional section rrsets yet) */
static int
msg_add_rrset_ns(struct auth_zone* z, struct regional* region,
struct dns_msg* msg, struct auth_data* node, struct auth_rrset* rrset)
@@ -1950,6 +1950,17 @@ static int auth_zone_zonemd_check_hash(struct auth_zone* z,
return 0;
}
+/** find the apex SOA RRset, if it exists */
+struct auth_rrset* auth_zone_get_soa_rrset(struct auth_zone* z)
+{
+ struct auth_data* apex;
+ struct auth_rrset* soa;
+ apex = az_find_name(z, z->name, z->namelen);
+ if(!apex) return NULL;
+ soa = az_domain_rrset(apex, LDNS_RR_TYPE_SOA);
+ return soa;
+}
+
/** find serial number of zone or false if none */
int
auth_zone_get_serial(struct auth_zone* z, uint32_t* serial)
@@ -3507,7 +3518,7 @@ auth_error_encode(struct query_info* qinfo, struct module_env* env,
if(!inplace_cb_reply_local_call(env, qinfo, NULL, NULL,
rcode, edns, repinfo, temp, env->now_tv))
- edns->opt_list = NULL;
+ edns->opt_list_inplace_cb_out = NULL;
error_encode(buf, rcode|BIT_AA, qinfo,
*(uint16_t*)sldns_buffer_begin(buf),
sldns_buffer_read_u16_at(buf, 2), edns);
@@ -5347,7 +5358,9 @@ xfr_transfer_lookup_host(struct auth_xfer* xfr, struct module_env* env)
edns.ext_rcode = 0;
edns.edns_version = 0;
edns.bits = EDNS_DO;
- edns.opt_list = NULL;
+ edns.opt_list_in = NULL;
+ edns.opt_list_out = NULL;
+ edns.opt_list_inplace_cb_out = NULL;
edns.padding_block_size = 0;
if(sldns_buffer_capacity(buf) < 65535)
edns.udp_size = (uint16_t)sldns_buffer_capacity(buf);
@@ -6480,7 +6493,7 @@ auth_xfer_probe_udp_callback(struct comm_point* c, void* arg, int err,
comm_point_delete(xfr->task_probe->cp);
xfr->task_probe->cp = NULL;
- /* if the result was not a successfull probe, we need
+ /* if the result was not a successful probe, we need
* to send the next one */
xfr_probe_nextmaster(xfr);
xfr_probe_send_or_end(xfr, env);
@@ -6536,7 +6549,9 @@ xfr_probe_lookup_host(struct auth_xfer* xfr, struct module_env* env)
edns.ext_rcode = 0;
edns.edns_version = 0;
edns.bits = EDNS_DO;
- edns.opt_list = NULL;
+ edns.opt_list_in = NULL;
+ edns.opt_list_out = NULL;
+ edns.opt_list_inplace_cb_out = NULL;
edns.padding_block_size = 0;
if(sldns_buffer_capacity(buf) < 65535)
edns.udp_size = (uint16_t)sldns_buffer_capacity(buf);
@@ -7149,7 +7164,7 @@ parse_url(char* url, char** host, char** file, int* port, int* ssl)
while(p && *p == '/')
p++;
if(!p || p[0] == 0)
- *file = strdup("index.html");
+ *file = strdup("/");
else *file = strdup(p);
if(!*file) {
log_err("malloc failure");
@@ -7683,7 +7698,7 @@ static void auth_zone_log(uint8_t* name, enum verbosity_value level,
static int zonemd_dnssec_verify_rrset(struct auth_zone* z,
struct module_env* env, struct module_stack* mods,
struct ub_packed_rrset_key* dnskey, struct auth_data* node,
- struct auth_rrset* rrset, char** why_bogus)
+ struct auth_rrset* rrset, char** why_bogus, uint8_t* sigalg)
{
struct ub_packed_rrset_key pk;
enum sec_status sec;
@@ -7711,7 +7726,7 @@ static int zonemd_dnssec_verify_rrset(struct auth_zone* z,
auth_zone_log(z->name, VERB_ALGO,
"zonemd: verify %s RRset with DNSKEY", typestr);
}
- sec = dnskeyset_verify_rrset(env, ve, &pk, dnskey, NULL, why_bogus,
+ sec = dnskeyset_verify_rrset(env, ve, &pk, dnskey, sigalg, why_bogus,
LDNS_SECTION_ANSWER, NULL);
if(sec == sec_status_secure) {
return 1;
@@ -7755,7 +7770,7 @@ static int nsec3_of_param_has_type(struct auth_rrset* nsec3, int algo,
static int zonemd_check_dnssec_absence(struct auth_zone* z,
struct module_env* env, struct module_stack* mods,
struct ub_packed_rrset_key* dnskey, struct auth_data* apex,
- char** reason, char** why_bogus)
+ char** reason, char** why_bogus, uint8_t* sigalg)
{
struct auth_rrset* nsec = NULL;
if(!apex) {
@@ -7767,7 +7782,7 @@ static int zonemd_check_dnssec_absence(struct auth_zone* z,
struct ub_packed_rrset_key pk;
/* dnssec verify the NSEC */
if(!zonemd_dnssec_verify_rrset(z, env, mods, dnskey, apex,
- nsec, why_bogus)) {
+ nsec, why_bogus, sigalg)) {
*reason = "DNSSEC verify failed for NSEC RRset";
return 0;
}
@@ -7810,7 +7825,7 @@ static int zonemd_check_dnssec_absence(struct auth_zone* z,
}
/* dnssec verify the NSEC3 */
if(!zonemd_dnssec_verify_rrset(z, env, mods, dnskey, match,
- nsec3, why_bogus)) {
+ nsec3, why_bogus, sigalg)) {
*reason = "DNSSEC verify failed for NSEC3 RRset";
return 0;
}
@@ -7831,7 +7846,8 @@ static int zonemd_check_dnssec_absence(struct auth_zone* z,
static int zonemd_check_dnssec_soazonemd(struct auth_zone* z,
struct module_env* env, struct module_stack* mods,
struct ub_packed_rrset_key* dnskey, struct auth_data* apex,
- struct auth_rrset* zonemd_rrset, char** reason, char** why_bogus)
+ struct auth_rrset* zonemd_rrset, char** reason, char** why_bogus,
+ uint8_t* sigalg)
{
struct auth_rrset* soa;
if(!apex) {
@@ -7844,12 +7860,12 @@ static int zonemd_check_dnssec_soazonemd(struct auth_zone* z,
return 0;
}
if(!zonemd_dnssec_verify_rrset(z, env, mods, dnskey, apex, soa,
- why_bogus)) {
+ why_bogus, sigalg)) {
*reason = "DNSSEC verify failed for SOA RRset";
return 0;
}
if(!zonemd_dnssec_verify_rrset(z, env, mods, dnskey, apex,
- zonemd_rrset, why_bogus)) {
+ zonemd_rrset, why_bogus, sigalg)) {
*reason = "DNSSEC verify failed for ZONEMD RRset";
return 0;
}
@@ -7908,12 +7924,14 @@ static void auth_zone_zonemd_fail(struct auth_zone* z, struct module_env* env,
* @param is_insecure: if true, the dnskey is not used, the zone is insecure.
* And dnssec is not used. It is DNSSEC secure insecure or not under
* a trust anchor.
+ * @param sigalg: if nonNULL provide algorithm downgrade protection.
+ * Otherwise one algorithm is enough. Must have space of ALGO_NEEDS_MAX+1.
* @param result: if not NULL result reason copied here.
*/
static void
auth_zone_verify_zonemd_with_key(struct auth_zone* z, struct module_env* env,
struct module_stack* mods, struct ub_packed_rrset_key* dnskey,
- int is_insecure, char** result)
+ int is_insecure, char** result, uint8_t* sigalg)
{
char* reason = NULL, *why_bogus = NULL;
struct auth_data* apex = NULL;
@@ -7943,7 +7961,7 @@ auth_zone_verify_zonemd_with_key(struct auth_zone* z, struct module_env* env,
} else if(!zonemd_rrset && dnskey && !is_insecure) {
/* fetch, DNSSEC verify, and check NSEC/NSEC3 */
if(!zonemd_check_dnssec_absence(z, env, mods, dnskey, apex,
- &reason, &why_bogus)) {
+ &reason, &why_bogus, sigalg)) {
auth_zone_zonemd_fail(z, env, reason, why_bogus, result);
return;
}
@@ -7951,7 +7969,7 @@ auth_zone_verify_zonemd_with_key(struct auth_zone* z, struct module_env* env,
} else if(zonemd_rrset && dnskey && !is_insecure) {
/* check DNSSEC verify of SOA and ZONEMD */
if(!zonemd_check_dnssec_soazonemd(z, env, mods, dnskey, apex,
- zonemd_rrset, &reason, &why_bogus)) {
+ zonemd_rrset, &reason, &why_bogus, sigalg)) {
auth_zone_zonemd_fail(z, env, reason, why_bogus, result);
return;
}
@@ -8065,15 +8083,78 @@ zonemd_get_dnskey_from_anchor(struct auth_zone* z, struct module_env* env,
return NULL;
}
+/** verify the DNSKEY from the zone with looked up DS record */
+static struct ub_packed_rrset_key*
+auth_zone_verify_zonemd_key_with_ds(struct auth_zone* z,
+ struct module_env* env, struct module_stack* mods,
+ struct ub_packed_rrset_key* ds, int* is_insecure, char** why_bogus,
+ struct ub_packed_rrset_key* keystorage, uint8_t* sigalg)
+{
+ struct auth_data* apex;
+ struct auth_rrset* dnskey_rrset;
+ enum sec_status sec;
+ struct val_env* ve;
+ int m;
+
+ /* fetch DNSKEY from zone data */
+ apex = az_find_name(z, z->name, z->namelen);
+ if(!apex) {
+ *why_bogus = "in verifywithDS, zone has no apex";
+ return NULL;
+ }
+ dnskey_rrset = az_domain_rrset(apex, LDNS_RR_TYPE_DNSKEY);
+ if(!dnskey_rrset || dnskey_rrset->data->count==0) {
+ *why_bogus = "in verifywithDS, zone has no DNSKEY";
+ return NULL;
+ }
+
+ m = modstack_find(mods, "validator");
+ if(m == -1) {
+ *why_bogus = "in verifywithDS, have no validator module";
+ return NULL;
+ }
+ ve = (struct val_env*)env->modinfo[m];
+
+ memset(keystorage, 0, sizeof(*keystorage));
+ keystorage->entry.key = keystorage;
+ keystorage->entry.data = dnskey_rrset->data;
+ keystorage->rk.dname = apex->name;
+ keystorage->rk.dname_len = apex->namelen;
+ keystorage->rk.type = htons(LDNS_RR_TYPE_DNSKEY);
+ keystorage->rk.rrset_class = htons(z->dclass);
+ auth_zone_log(z->name, VERB_QUERY, "zonemd: verify zone DNSKEY with DS");
+ sec = val_verify_DNSKEY_with_DS(env, ve, keystorage, ds, sigalg,
+ why_bogus, NULL);
+ regional_free_all(env->scratch);
+ if(sec == sec_status_secure) {
+ /* success */
+ return keystorage;
+ } else if(sec == sec_status_insecure) {
+ /* insecure */
+ *is_insecure = 1;
+ } else {
+ /* bogus */
+ *is_insecure = 0;
+ if(*why_bogus == NULL)
+ *why_bogus = "verify failed";
+ auth_zone_log(z->name, VERB_ALGO,
+ "zonemd: verify DNSKEY RRset with DS failed: %s",
+ *why_bogus);
+ }
+ return NULL;
+}
+
/** callback for ZONEMD lookup of DNSKEY */
void auth_zonemd_dnskey_lookup_callback(void* arg, int rcode, sldns_buffer* buf,
enum sec_status sec, char* why_bogus, int ATTR_UNUSED(was_ratelimited))
{
struct auth_zone* z = (struct auth_zone*)arg;
struct module_env* env;
- char* reason = NULL;
- struct ub_packed_rrset_key* dnskey = NULL;
- int is_insecure = 0;
+ char* reason = NULL, *ds_bogus = NULL, *typestr="DNSKEY";
+ struct ub_packed_rrset_key* dnskey = NULL, *ds = NULL;
+ int is_insecure = 0, downprot;
+ struct ub_packed_rrset_key keystorage;
+ uint8_t sigalg[ALGO_NEEDS_MAX+1];
lock_rw_wrlock(&z->lock);
env = z->zonemd_callback_env;
@@ -8084,16 +8165,22 @@ void auth_zonemd_dnskey_lookup_callback(void* arg, int rcode, sldns_buffer* buf,
lock_rw_unlock(&z->lock);
return; /* stop on quit */
}
+ if(z->zonemd_callback_qtype == LDNS_RR_TYPE_DS)
+ typestr = "DS";
+ downprot = env->cfg->harden_algo_downgrade;
/* process result */
if(sec == sec_status_bogus) {
reason = why_bogus;
- if(!reason)
- reason = "lookup of DNSKEY was bogus";
+ if(!reason) {
+ if(z->zonemd_callback_qtype == LDNS_RR_TYPE_DNSKEY)
+ reason = "lookup of DNSKEY was bogus";
+ else reason = "lookup of DS was bogus";
+ }
auth_zone_log(z->name, VERB_ALGO,
- "zonemd lookup of DNSKEY was bogus: %s", reason);
+ "zonemd lookup of %s was bogus: %s", typestr, reason);
} else if(rcode == LDNS_RCODE_NOERROR) {
- uint16_t wanted_qtype = LDNS_RR_TYPE_DNSKEY;
+ uint16_t wanted_qtype = z->zonemd_callback_qtype;
struct regional* temp = env->scratch;
struct query_info rq;
struct reply_info* rep;
@@ -8106,25 +8193,29 @@ void auth_zonemd_dnskey_lookup_callback(void* arg, int rcode, sldns_buffer* buf,
struct ub_packed_rrset_key* answer =
reply_find_answer_rrset(&rq, rep);
if(answer && sec == sec_status_secure) {
- dnskey = answer;
+ if(z->zonemd_callback_qtype == LDNS_RR_TYPE_DNSKEY)
+ dnskey = answer;
+ else ds = answer;
auth_zone_log(z->name, VERB_ALGO,
- "zonemd lookup of DNSKEY was secure");
+ "zonemd lookup of %s was secure", typestr);
} else if(sec == sec_status_secure && !answer) {
is_insecure = 1;
auth_zone_log(z->name, VERB_ALGO,
- "zonemd lookup of DNSKEY has no content, but is secure, treat as insecure");
+ "zonemd lookup of %s has no content, but is secure, treat as insecure", typestr);
} else if(sec == sec_status_insecure) {
is_insecure = 1;
auth_zone_log(z->name, VERB_ALGO,
- "zonemd lookup of DNSKEY was insecure");
+ "zonemd lookup of %s was insecure", typestr);
} else if(sec == sec_status_indeterminate) {
is_insecure = 1;
auth_zone_log(z->name, VERB_ALGO,
- "zonemd lookup of DNSKEY was indeterminate, treat as insecure");
+ "zonemd lookup of %s was indeterminate, treat as insecure", typestr);
} else {
auth_zone_log(z->name, VERB_ALGO,
- "zonemd lookup of DNSKEY has nodata");
- reason = "lookup of DNSKEY has nodata";
+ "zonemd lookup of %s has nodata", typestr);
+ if(z->zonemd_callback_qtype == LDNS_RR_TYPE_DNSKEY)
+ reason = "lookup of DNSKEY has nodata";
+ else reason = "lookup of DS has nodata";
}
} else if(rep && rq.qtype == wanted_qtype &&
query_dname_compare(z->name, rq.qname) == 0 &&
@@ -8137,40 +8228,52 @@ void auth_zonemd_dnskey_lookup_callback(void* arg, int rcode, sldns_buffer* buf,
* trust, as insecure. */
is_insecure = 1;
auth_zone_log(z->name, VERB_ALGO,
- "zonemd lookup of DNSKEY was secure NXDOMAIN, treat as insecure");
+ "zonemd lookup of %s was secure NXDOMAIN, treat as insecure", typestr);
} else if(rep && rq.qtype == wanted_qtype &&
query_dname_compare(z->name, rq.qname) == 0 &&
FLAGS_GET_RCODE(rep->flags) == LDNS_RCODE_NXDOMAIN &&
sec == sec_status_insecure) {
is_insecure = 1;
auth_zone_log(z->name, VERB_ALGO,
- "zonemd lookup of DNSKEY was insecure NXDOMAIN, treat as insecure");
+ "zonemd lookup of %s was insecure NXDOMAIN, treat as insecure", typestr);
} else if(rep && rq.qtype == wanted_qtype &&
query_dname_compare(z->name, rq.qname) == 0 &&
FLAGS_GET_RCODE(rep->flags) == LDNS_RCODE_NXDOMAIN &&
sec == sec_status_indeterminate) {
is_insecure = 1;
auth_zone_log(z->name, VERB_ALGO,
- "zonemd lookup of DNSKEY was indeterminate NXDOMAIN, treat as insecure");
+ "zonemd lookup of %s was indeterminate NXDOMAIN, treat as insecure", typestr);
} else {
auth_zone_log(z->name, VERB_ALGO,
- "zonemd lookup of DNSKEY has no answer");
- reason = "lookup of DNSKEY has no answer";
+ "zonemd lookup of %s has no answer", typestr);
+ if(z->zonemd_callback_qtype == LDNS_RR_TYPE_DNSKEY)
+ reason = "lookup of DNSKEY has no answer";
+ else reason = "lookup of DS has no answer";
}
} else {
auth_zone_log(z->name, VERB_ALGO,
- "zonemd lookup of DNSKEY failed");
- reason = "lookup of DNSKEY failed";
+ "zonemd lookup of %s failed", typestr);
+ if(z->zonemd_callback_qtype == LDNS_RR_TYPE_DNSKEY)
+ reason = "lookup of DNSKEY failed";
+ else reason = "lookup of DS failed";
+ }
+
+ if(!reason && !is_insecure && !dnskey && ds) {
+ dnskey = auth_zone_verify_zonemd_key_with_ds(z, env,
+ &env->mesh->mods, ds, &is_insecure, &ds_bogus,
+ &keystorage, downprot?sigalg:NULL);
+ if(!dnskey && !is_insecure && !reason)
+ reason = "DNSKEY verify with DS failed";
}
if(reason) {
- auth_zone_zonemd_fail(z, env, reason, NULL, NULL);
+ auth_zone_zonemd_fail(z, env, reason, ds_bogus, NULL);
lock_rw_unlock(&z->lock);
return;
}
auth_zone_verify_zonemd_with_key(z, env, &env->mesh->mods, dnskey,
- is_insecure, NULL);
+ is_insecure, NULL, downprot?sigalg:NULL);
regional_free_all(env->scratch);
lock_rw_unlock(&z->lock);
}
@@ -8183,14 +8286,21 @@ zonemd_lookup_dnskey(struct auth_zone* z, struct module_env* env)
uint16_t qflags = BIT_RD;
struct edns_data edns;
sldns_buffer* buf = env->scratch_buffer;
+ int fetch_ds = 0;
+ if(!z->fallback_enabled) {
+ /* we cannot actually get the DNSKEY, because it is in the
+ * zone we have ourselves, and it is not served yet
+ * (possibly), so fetch type DS */
+ fetch_ds = 1;
+ }
if(z->zonemd_callback_env) {
/* another worker is already working on the callback
* for the DNSKEY lookup for ZONEMD verification.
* We do not also have to do ZONEMD verification, let that
* worker do it */
auth_zone_log(z->name, VERB_ALGO,
- "zonemd needs lookup of DNSKEY and that already worked on by another worker");
+ "zonemd needs lookup of %s and that already is worked on by another worker", (fetch_ds?"DS":"DNSKEY"));
return 1;
}
@@ -8199,21 +8309,26 @@ zonemd_lookup_dnskey(struct auth_zone* z, struct module_env* env)
qinfo.qname_len = z->namelen;
qinfo.qname = z->name;
qinfo.qclass = z->dclass;
- qinfo.qtype = LDNS_RR_TYPE_DNSKEY;
+ if(fetch_ds)
+ qinfo.qtype = LDNS_RR_TYPE_DS;
+ else qinfo.qtype = LDNS_RR_TYPE_DNSKEY;
qinfo.local_alias = NULL;
if(verbosity >= VERB_ALGO) {
char buf1[512];
char buf2[LDNS_MAX_DOMAINLEN+1];
dname_str(z->name, buf2);
- snprintf(buf1, sizeof(buf1), "auth zone %s: lookup DNSKEY "
- "for zonemd verification", buf2);
+ snprintf(buf1, sizeof(buf1), "auth zone %s: lookup %s "
+ "for zonemd verification", buf2,
+ (fetch_ds?"DS":"DNSKEY"));
log_query_info(VERB_ALGO, buf1, &qinfo);
}
edns.edns_present = 1;
edns.ext_rcode = 0;
edns.edns_version = 0;
edns.bits = EDNS_DO;
- edns.opt_list = NULL;
+ edns.opt_list_in = NULL;
+ edns.opt_list_out = NULL;
+ edns.opt_list_inplace_cb_out = NULL;
if(sldns_buffer_capacity(buf) < 65535)
edns.udp_size = (uint16_t)sldns_buffer_capacity(buf);
else edns.udp_size = 65535;
@@ -8221,12 +8336,14 @@ zonemd_lookup_dnskey(struct auth_zone* z, struct module_env* env)
/* store the worker-specific module env for the callback.
* We can then reference this when the callback executes */
z->zonemd_callback_env = env;
+ z->zonemd_callback_qtype = qinfo.qtype;
/* the callback can be called straight away */
lock_rw_unlock(&z->lock);
if(!mesh_new_callback(env->mesh, &qinfo, qflags, &edns, buf, 0,
&auth_zonemd_dnskey_lookup_callback, z)) {
lock_rw_wrlock(&z->lock);
- log_err("out of memory lookup up dnskey for zonemd");
+ log_err("out of memory lookup of %s for zonemd",
+ (fetch_ds?"DS":"DNSKEY"));
return 0;
}
lock_rw_wrlock(&z->lock);
@@ -8245,6 +8362,8 @@ void auth_zone_verify_zonemd(struct auth_zone* z, struct module_env* env,
* If not present check if absence is allowed by DNSSEC */
if(!z->zonemd_check)
return;
+ if(z->data.count == 0)
+ return; /* no data */
/* if zone is under a trustanchor */
/* is it equal to trustanchor - get dnskey's verified */
@@ -8298,7 +8417,7 @@ void auth_zone_verify_zonemd(struct auth_zone* z, struct module_env* env,
}
auth_zone_verify_zonemd_with_key(z, env, mods, dnskey, is_insecure,
- result);
+ result, NULL);
regional_free_all(env->scratch);
}
diff --git a/contrib/unbound/services/authzone.h b/contrib/unbound/services/authzone.h
index ffe234d59b53..d24e569d3b85 100644
--- a/contrib/unbound/services/authzone.h
+++ b/contrib/unbound/services/authzone.h
@@ -143,6 +143,8 @@ struct auth_zone {
* worker has already picked up the zonemd verification task and
* this worker does not have to do it as well. */
struct module_env* zonemd_callback_env;
+ /** for the zonemd callback, the type of data looked up */
+ uint16_t zonemd_callback_qtype;
/** zone has been deleted */
int zone_deleted;
/** deletelist pointer, unused normally except during delete */
@@ -634,6 +636,9 @@ int auth_zones_startprobesequence(struct auth_zones* az,
/** read auth zone from zonefile. caller must lock zone. false on failure */
int auth_zone_read_zonefile(struct auth_zone* z, struct config_file* cfg);
+/** find the apex SOA RRset, if it exists. NULL if no SOA RRset. */
+struct auth_rrset* auth_zone_get_soa_rrset(struct auth_zone* z);
+
/** find serial number of zone or false if none (no SOA record) */
int auth_zone_get_serial(struct auth_zone* z, uint32_t* serial);
diff --git a/contrib/unbound/services/cache/rrset.h b/contrib/unbound/services/cache/rrset.h
index 35a0d732b048..7c36d4032ebc 100644
--- a/contrib/unbound/services/cache/rrset.h
+++ b/contrib/unbound/services/cache/rrset.h
@@ -120,7 +120,7 @@ void rrset_cache_touch(struct rrset_cache* r, struct ub_packed_rrset_key* key,
* the new rrset. The reference may be changed if the cached rrset is
* superior.
* Before calling the rrset is presumed newly allocated and changeable.
- * Afer calling you do not hold a lock, and the rrset is inserted in
+ * After calling you do not hold a lock, and the rrset is inserted in
* the hashtable so you need a lock to change it.
* @param alloc: how to allocate (and deallocate) the special rrset key.
* @param timenow: current time (to see if ttl in cache is expired).
@@ -143,7 +143,7 @@ int rrset_cache_update(struct rrset_cache* r, struct rrset_ref* ref,
* @param rrset: which rrset to cache as wildcard. This rrset is left
* untouched.
* @param ce: the closest encloser, will be uses to generate the wildcard dname.
- * @param ce_len: the closest encloser lenght.
+ * @param ce_len: the closest encloser length.
* @param alloc: how to allocate (and deallocate) the special rrset key.
* @param timenow: current time (to see if ttl in cache is expired).
*/
diff --git a/contrib/unbound/services/listen_dnsport.c b/contrib/unbound/services/listen_dnsport.c
index b43def567501..6a33fbcdaf7e 100644
--- a/contrib/unbound/services/listen_dnsport.c
+++ b/contrib/unbound/services/listen_dnsport.c
@@ -869,9 +869,14 @@ set_ip_dscp(int socket, int addrfamily, int dscp)
ds = dscp << 2;
switch(addrfamily) {
case AF_INET6:
- if(setsockopt(socket, IPPROTO_IPV6, IPV6_TCLASS, (void*)&ds, sizeof(ds)) < 0)
+ #ifdef IPV6_TCLASS
+ if(setsockopt(socket, IPPROTO_IPV6, IPV6_TCLASS, (void*)&ds,
+ sizeof(ds)) < 0)
return sock_strerror(errno);
break;
+ #else
+ return "IPV6_TCLASS not defined on this system";
+ #endif
default:
if(setsockopt(socket, IPPROTO_IP, IP_TOS, (void*)&ds, sizeof(ds)) < 0)
return sock_strerror(errno);
@@ -1306,6 +1311,38 @@ listen_cp_insert(struct comm_point* c, struct listen_dnsport* front)
return 1;
}
+void listen_setup_locks(void)
+{
+ if(!stream_wait_lock_inited) {
+ lock_basic_init(&stream_wait_count_lock);
+ stream_wait_lock_inited = 1;
+ }
+ if(!http2_query_buffer_lock_inited) {
+ lock_basic_init(&http2_query_buffer_count_lock);
+ http2_query_buffer_lock_inited = 1;
+ }
+ if(!http2_response_buffer_lock_inited) {
+ lock_basic_init(&http2_response_buffer_count_lock);
+ http2_response_buffer_lock_inited = 1;
+ }
+}
+
+void listen_desetup_locks(void)
+{
+ if(stream_wait_lock_inited) {
+ stream_wait_lock_inited = 0;
+ lock_basic_destroy(&stream_wait_count_lock);
+ }
+ if(http2_query_buffer_lock_inited) {
+ http2_query_buffer_lock_inited = 0;
+ lock_basic_destroy(&http2_query_buffer_count_lock);
+ }
+ if(http2_response_buffer_lock_inited) {
+ http2_response_buffer_lock_inited = 0;
+ lock_basic_destroy(&http2_response_buffer_count_lock);
+ }
+}
+
struct listen_dnsport*
listen_create(struct comm_base* base, struct listen_port* ports,
size_t bufsize, int tcp_accept_count, int tcp_idle_timeout,
@@ -1327,18 +1364,6 @@ listen_create(struct comm_base* base, struct listen_port* ports,
free(front);
return NULL;
}
- if(!stream_wait_lock_inited) {
- lock_basic_init(&stream_wait_count_lock);
- stream_wait_lock_inited = 1;
- }
- if(!http2_query_buffer_lock_inited) {
- lock_basic_init(&http2_query_buffer_count_lock);
- http2_query_buffer_lock_inited = 1;
- }
- if(!http2_response_buffer_lock_inited) {
- lock_basic_init(&http2_response_buffer_count_lock);
- http2_response_buffer_lock_inited = 1;
- }
/* create comm points as needed */
while(ports) {
@@ -1454,18 +1479,6 @@ listen_delete(struct listen_dnsport* front)
#endif
sldns_buffer_free(front->udp_buff);
free(front);
- if(stream_wait_lock_inited) {
- stream_wait_lock_inited = 0;
- lock_basic_destroy(&stream_wait_count_lock);
- }
- if(http2_query_buffer_lock_inited) {
- http2_query_buffer_lock_inited = 0;
- lock_basic_destroy(&http2_query_buffer_count_lock);
- }
- if(http2_response_buffer_lock_inited) {
- http2_response_buffer_lock_inited = 0;
- lock_basic_destroy(&http2_response_buffer_count_lock);
- }
}
#ifdef HAVE_GETIFADDRS
@@ -2610,7 +2623,7 @@ static int http2_req_begin_headers_cb(nghttp2_session* session,
int ret;
if(frame->hd.type != NGHTTP2_HEADERS ||
frame->headers.cat != NGHTTP2_HCAT_REQUEST) {
- /* only interrested in request headers */
+ /* only interested in request headers */
return 0;
}
if(!(h2_stream = http2_stream_create(frame->hd.stream_id))) {
@@ -2738,7 +2751,7 @@ static int http2_req_header_cb(nghttp2_session* session,
* the HEADER */
if(frame->hd.type != NGHTTP2_HEADERS ||
frame->headers.cat != NGHTTP2_HCAT_REQUEST) {
- /* only interrested in request headers */
+ /* only interested in request headers */
return 0;
}
if(!(h2_stream = nghttp2_session_get_stream_user_data(session,
@@ -2834,7 +2847,7 @@ static int http2_req_header_cb(nghttp2_session* session,
h2_stream->query_too_large = 1;
return 0;
}
- /* guaranteed to only contian digits and be null terminated */
+ /* guaranteed to only contain digits and be null terminated */
h2_stream->content_length = atoi((const char*)value);
if(h2_stream->content_length >
h2_session->c->http2_stream_max_qbuffer_size) {
@@ -2874,7 +2887,7 @@ static int http2_req_data_chunk_recv_cb(nghttp2_session* ATTR_UNUSED(session),
/* setting this to msg-buffer-size can result in a lot
* of memory consuption. Most queries should fit in a
* single DATA frame, and most POST queries will
- * containt content-length which does not impose this
+ * contain content-length which does not impose this
* limit. */
qlen = len;
}
diff --git a/contrib/unbound/services/listen_dnsport.h b/contrib/unbound/services/listen_dnsport.h
index 1e51be9bfcab..0e63236bcbce 100644
--- a/contrib/unbound/services/listen_dnsport.h
+++ b/contrib/unbound/services/listen_dnsport.h
@@ -199,6 +199,11 @@ listen_create(struct comm_base* base, struct listen_port* ports,
*/
void listen_delete(struct listen_dnsport* listen);
+/** setup the locks for the listen ports */
+void listen_setup_locks(void);
+/** desetup the locks for the listen ports */
+void listen_desetup_locks(void);
+
/**
* delete listen_list of commpoints. Calls commpointdelete() on items.
* This may close the fds or not depending on flags.
diff --git a/contrib/unbound/services/localzone.c b/contrib/unbound/services/localzone.c
index 54f55ab810e4..77d0107f9f6f 100644
--- a/contrib/unbound/services/localzone.c
+++ b/contrib/unbound/services/localzone.c
@@ -465,7 +465,7 @@ lz_find_create_node(struct local_zone* z, uint8_t* nm, size_t nmlen,
/* Mark the SOA record for the zone. This only marks the SOA rrset; the data
* for the RR is entered later on local_zone_enter_rr() as with the other
- * records. An artifical soa_negative record with a modified TTL (minimum of
+ * records. An artificial soa_negative record with a modified TTL (minimum of
* the TTL and the SOA.MINIMUM) is also created and marked for usage with
* negative answers and to avoid allocations during those answers. */
static int
@@ -898,6 +898,11 @@ int local_zone_enter_defaults(struct local_zones* zones, struct config_file* cfg
}
lock_rw_unlock(&z->lock);
}
+ /* home.arpa. zone (RFC 8375) */
+ if(!add_empty_default(zones, cfg, "home.arpa.")) {
+ log_err("out of memory adding default zone");
+ return 0;
+ }
/* onion. zone (RFC 7686) */
if(!add_empty_default(zones, cfg, "onion.")) {
log_err("out of memory adding default zone");
@@ -1294,7 +1299,7 @@ local_error_encode(struct query_info* qinfo, struct module_env* env,
if(!inplace_cb_reply_local_call(env, qinfo, NULL, NULL,
rcode, edns, repinfo, temp, env->now_tv))
- edns->opt_list = NULL;
+ edns->opt_list_inplace_cb_out = NULL;
error_encode(buf, r, qinfo, *(uint16_t*)sldns_buffer_begin(buf),
sldns_buffer_read_u16_at(buf, 2), edns);
}
@@ -1521,7 +1526,7 @@ local_data_answer(struct local_zone* z, struct module_env* env,
/* write qname */
memmove(d->rr_data[0] + sizeof(uint16_t), qinfo->qname,
qinfo->qname_len - 1);
- /* write cname target wilcard wildcard label */
+ /* write cname target wildcard label */
memmove(d->rr_data[0] + sizeof(uint16_t) +
qinfo->qname_len - 1, ctarget + 2,
ctargetlen - 2);
@@ -1570,6 +1575,15 @@ local_zone_does_not_cover(struct local_zone* z, struct query_info* qinfo,
return (lr == NULL);
}
+static inline int
+local_zone_is_udp_query(struct comm_reply* repinfo) {
+ return repinfo != NULL
+ ? (repinfo->c != NULL
+ ? repinfo->c->type == comm_udp
+ : 0)
+ : 0;
+}
+
int
local_zones_zone_answer(struct local_zone* z, struct module_env* env,
struct query_info* qinfo, struct edns_data* edns,
@@ -1592,7 +1606,9 @@ local_zones_zone_answer(struct local_zone* z, struct module_env* env,
lz_type == local_zone_redirect ||
lz_type == local_zone_inform_redirect ||
lz_type == local_zone_always_nxdomain ||
- lz_type == local_zone_always_nodata) {
+ lz_type == local_zone_always_nodata ||
+ (lz_type == local_zone_truncate
+ && local_zone_is_udp_query(repinfo))) {
/* for static, reply nodata or nxdomain
* for redirect, reply nodata */
/* no additional section processing,
@@ -1602,9 +1618,11 @@ local_zones_zone_answer(struct local_zone* z, struct module_env* env,
*/
int rcode = (ld || lz_type == local_zone_redirect ||
lz_type == local_zone_inform_redirect ||
- lz_type == local_zone_always_nodata)?
+ lz_type == local_zone_always_nodata ||
+ lz_type == local_zone_truncate)?
LDNS_RCODE_NOERROR:LDNS_RCODE_NXDOMAIN;
- if(z->soa && z->soa_negative)
+ rcode = (lz_type == local_zone_truncate ? (rcode|BIT_TC) : rcode);
+ if(z != NULL && z->soa && z->soa_negative)
return local_encode(qinfo, env, edns, repinfo, buf, temp,
z->soa_negative, 0, rcode);
local_error_encode(qinfo, env, edns, repinfo, buf, temp, rcode,
@@ -1661,7 +1679,7 @@ local_zones_zone_answer(struct local_zone* z, struct module_env* env,
* does not, then we should make this noerror/nodata */
if(ld && ld->rrsets) {
int rcode = LDNS_RCODE_NOERROR;
- if(z->soa && z->soa_negative)
+ if(z != NULL && z->soa && z->soa_negative)
return local_encode(qinfo, env, edns, repinfo, buf, temp,
z->soa_negative, 0, rcode);
local_error_encode(qinfo, env, edns, repinfo, buf, temp, rcode,
@@ -1860,6 +1878,7 @@ const char* local_zone_type2str(enum localzone_type t)
case local_zone_always_deny: return "always_deny";
case local_zone_always_null: return "always_null";
case local_zone_noview: return "noview";
+ case local_zone_truncate: return "truncate";
case local_zone_invalid: return "invalid";
}
return "badtyped";
@@ -1899,6 +1918,8 @@ int local_zone_str2type(const char* type, enum localzone_type* t)
*t = local_zone_always_null;
else if(strcmp(type, "noview") == 0)
*t = local_zone_noview;
+ else if(strcmp(type, "truncate") == 0)
+ *t = local_zone_truncate;
else if(strcmp(type, "nodefault") == 0)
*t = local_zone_nodefault;
else return 0;
diff --git a/contrib/unbound/services/localzone.h b/contrib/unbound/services/localzone.h
index b52d81dc72cb..19534f7509ed 100644
--- a/contrib/unbound/services/localzone.h
+++ b/contrib/unbound/services/localzone.h
@@ -101,6 +101,8 @@ enum localzone_type {
local_zone_always_null,
/** answer not from the view, but global or no-answer */
local_zone_noview,
+ /** truncate the response; client should retry via tcp */
+ local_zone_truncate,
/** Invalid type, cannot be used to generate answer */
local_zone_invalid
};
@@ -255,7 +257,7 @@ void local_zone_delete(struct local_zone* z);
* @param dclass: class to lookup.
* @param dtype: type to lookup, if type DS a zone higher is used for zonecuts.
* @param taglist: taglist to lookup.
- * @param taglen: lenth of taglist.
+ * @param taglen: length of taglist.
* @param ignoretags: lookup zone by name and class, regardless the
* local-zone's tags.
* @return closest local_zone or NULL if no covering zone is found.
@@ -563,6 +565,8 @@ enum respip_action {
respip_always_nodata = local_zone_always_nodata,
/** answer with nodata response */
respip_always_deny = local_zone_always_deny,
+ /** RPZ: truncate answer in order to force switch to tcp */
+ respip_truncate = local_zone_truncate,
/* The rest of the values are only possible as
* access-control-tag-action */
diff --git a/contrib/unbound/services/mesh.c b/contrib/unbound/services/mesh.c
index 5679a8b64e58..cdcfedda270c 100644
--- a/contrib/unbound/services/mesh.c
+++ b/contrib/unbound/services/mesh.c
@@ -461,7 +461,7 @@ void mesh_new_client(struct mesh_area* mesh, struct query_info* qinfo,
struct edns_data* edns, struct comm_reply* rep, uint16_t qid)
{
struct mesh_state* s = NULL;
- int unique = unique_mesh_state(edns->opt_list, mesh->env);
+ int unique = unique_mesh_state(edns->opt_list_in, mesh->env);
int was_detached = 0;
int was_noreply = 0;
int added = 0;
@@ -505,7 +505,7 @@ void mesh_new_client(struct mesh_area* mesh, struct query_info* qinfo,
log_err("mesh_state_create: out of memory; SERVFAIL");
if(!inplace_cb_reply_servfail_call(mesh->env, qinfo, NULL, NULL,
LDNS_RCODE_SERVFAIL, edns, rep, mesh->env->scratch, mesh->env->now_tv))
- edns->opt_list = NULL;
+ edns->opt_list_inplace_cb_out = NULL;
error_encode(r_buffer, LDNS_RCODE_SERVFAIL,
qinfo, qid, qflags, edns);
comm_point_send_reply(rep);
@@ -514,14 +514,14 @@ void mesh_new_client(struct mesh_area* mesh, struct query_info* qinfo,
if(unique)
mesh_state_make_unique(s);
/* copy the edns options we got from the front */
- if(edns->opt_list) {
- s->s.edns_opts_front_in = edns_opt_copy_region(edns->opt_list,
+ if(edns->opt_list_in) {
+ s->s.edns_opts_front_in = edns_opt_copy_region(edns->opt_list_in,
s->s.region);
if(!s->s.edns_opts_front_in) {
log_err("mesh_state_create: out of memory; SERVFAIL");
if(!inplace_cb_reply_servfail_call(mesh->env, qinfo, NULL,
NULL, LDNS_RCODE_SERVFAIL, edns, rep, mesh->env->scratch, mesh->env->now_tv))
- edns->opt_list = NULL;
+ edns->opt_list_inplace_cb_out = NULL;
error_encode(r_buffer, LDNS_RCODE_SERVFAIL,
qinfo, qid, qflags, edns);
comm_point_send_reply(rep);
@@ -594,7 +594,7 @@ void mesh_new_client(struct mesh_area* mesh, struct query_info* qinfo,
servfail_mem:
if(!inplace_cb_reply_servfail_call(mesh->env, qinfo, &s->s,
NULL, LDNS_RCODE_SERVFAIL, edns, rep, mesh->env->scratch, mesh->env->now_tv))
- edns->opt_list = NULL;
+ edns->opt_list_inplace_cb_out = NULL;
error_encode(r_buffer, LDNS_RCODE_SERVFAIL,
qinfo, qid, qflags, edns);
comm_point_send_reply(rep);
@@ -609,7 +609,7 @@ mesh_new_callback(struct mesh_area* mesh, struct query_info* qinfo,
uint16_t qid, mesh_cb_func_type cb, void* cb_arg)
{
struct mesh_state* s = NULL;
- int unique = unique_mesh_state(edns->opt_list, mesh->env);
+ int unique = unique_mesh_state(edns->opt_list_in, mesh->env);
int timeout = mesh->env->cfg->serve_expired?
mesh->env->cfg->serve_expired_client_timeout:0;
int was_detached = 0;
@@ -632,8 +632,8 @@ mesh_new_callback(struct mesh_area* mesh, struct query_info* qinfo,
}
if(unique)
mesh_state_make_unique(s);
- if(edns->opt_list) {
- s->s.edns_opts_front_in = edns_opt_copy_region(edns->opt_list,
+ if(edns->opt_list_in) {
+ s->s.edns_opts_front_in = edns_opt_copy_region(edns->opt_list_in,
s->s.region);
if(!s->s.edns_opts_front_in) {
return 0;
@@ -1145,11 +1145,11 @@ mesh_do_callback(struct mesh_state* m, int rcode, struct reply_info* rep,
if(rcode == LDNS_RCODE_SERVFAIL) {
if(!inplace_cb_reply_servfail_call(m->s.env, &m->s.qinfo, &m->s,
rep, rcode, &r->edns, NULL, m->s.region, start_time))
- r->edns.opt_list = NULL;
+ r->edns.opt_list_inplace_cb_out = NULL;
} else {
if(!inplace_cb_reply_call(m->s.env, &m->s.qinfo, &m->s, rep, rcode,
&r->edns, NULL, m->s.region, start_time))
- r->edns.opt_list = NULL;
+ r->edns.opt_list_inplace_cb_out = NULL;
}
fptr_ok(fptr_whitelist_mesh_cb(r->cb));
(*r->cb)(r->cb_arg, rcode, r->buf, sec_status_unchecked, NULL,
@@ -1183,6 +1183,22 @@ mesh_do_callback(struct mesh_state* m, int rcode, struct reply_info* rep,
m->s.env->mesh->num_reply_addrs--;
}
+static inline int
+mesh_is_rpz_respip_tcponly_action(struct mesh_state const* m)
+{
+ struct respip_action_info const* respip_info = m->s.respip_action_info;
+ return respip_info == NULL
+ ? 0
+ : (respip_info->rpz_used
+ && !respip_info->rpz_disabled
+ && respip_info->action == respip_truncate);
+}
+
+static inline int
+mesh_is_udp(struct mesh_reply const* r) {
+ return r->query_reply.c->type == comm_udp;
+}
+
/**
* Send reply to mesh reply entry
* @param m: mesh state to send it for.
@@ -1201,15 +1217,17 @@ mesh_send_reply(struct mesh_state* m, int rcode, struct reply_info* rep,
struct timeval end_time;
struct timeval duration;
int secure;
- /* Copy the client's EDNS for later restore, to make sure the edns
- * compare is with the correct edns options. */
- struct edns_data edns_bak = r->edns;
/* briefly set the replylist to null in case the
* meshsendreply calls tcpreqinfo sendreply that
* comm_point_drops because of size, and then the
* null stops the mesh state remove and thus
* reply_list modification and accounting */
struct mesh_reply* rlist = m->reply_list;
+
+ /* rpz: apply actions */
+ rcode = mesh_is_udp(r) && mesh_is_rpz_respip_tcponly_action(m)
+ ? (rcode|BIT_TC) : rcode;
+
/* examine security status */
if(m->s.env->need_to_validate && (!(r->qflags&BIT_CD) ||
m->s.env->cfg->ignore_cd) && rep &&
@@ -1248,8 +1266,9 @@ mesh_send_reply(struct mesh_state* m, int rcode, struct reply_info* rep,
prev->edns.edns_present == r->edns.edns_present &&
prev->edns.bits == r->edns.bits &&
prev->edns.udp_size == r->edns.udp_size &&
- edns_opt_list_compare(prev->edns.opt_list, r->edns.opt_list)
- == 0) {
+ edns_opt_list_compare(prev->edns.opt_list_out, r->edns.opt_list_out) == 0 &&
+ edns_opt_list_compare(prev->edns.opt_list_inplace_cb_out, r->edns.opt_list_inplace_cb_out) == 0
+ ) {
/* if the previous reply is identical to this one, fix ID */
if(prev_buffer != r_buffer)
sldns_buffer_copy(r_buffer, prev_buffer);
@@ -1265,11 +1284,11 @@ mesh_send_reply(struct mesh_state* m, int rcode, struct reply_info* rep,
if(rcode == LDNS_RCODE_SERVFAIL) {
if(!inplace_cb_reply_servfail_call(m->s.env, &m->s.qinfo, &m->s,
rep, rcode, &r->edns, &r->query_reply, m->s.region, &r->start_time))
- r->edns.opt_list = NULL;
+ r->edns.opt_list_inplace_cb_out = NULL;
} else {
if(!inplace_cb_reply_call(m->s.env, &m->s.qinfo, &m->s, rep, rcode,
&r->edns, &r->query_reply, m->s.region, &r->start_time))
- r->edns.opt_list = NULL;
+ r->edns.opt_list_inplace_cb_out = NULL;
}
error_encode(r_buffer, rcode, &m->s.qinfo, r->qid,
r->qflags, &r->edns);
@@ -1286,9 +1305,6 @@ mesh_send_reply(struct mesh_state* m, int rcode, struct reply_info* rep,
m->s.qinfo.local_alias = r->local_alias;
if(!inplace_cb_reply_call(m->s.env, &m->s.qinfo, &m->s, rep,
LDNS_RCODE_NOERROR, &r->edns, &r->query_reply, m->s.region, &r->start_time) ||
- !apply_edns_options(&r->edns, &edns_bak,
- m->s.env->cfg, r->query_reply.c,
- m->s.region) ||
!reply_info_answer_encode(&m->s.qinfo, rep, r->qid,
r->qflags, r_buffer, 0, 1, m->s.env->scratch,
udp_size, &r->edns, (int)(r->edns.bits & EDNS_DO),
@@ -1296,11 +1312,10 @@ mesh_send_reply(struct mesh_state* m, int rcode, struct reply_info* rep,
{
if(!inplace_cb_reply_servfail_call(m->s.env, &m->s.qinfo, &m->s,
rep, LDNS_RCODE_SERVFAIL, &r->edns, &r->query_reply, m->s.region, &r->start_time))
- r->edns.opt_list = NULL;
+ r->edns.opt_list_inplace_cb_out = NULL;
error_encode(r_buffer, LDNS_RCODE_SERVFAIL,
&m->s.qinfo, r->qid, r->qflags, &r->edns);
}
- r->edns = edns_bak;
m->reply_list = NULL;
comm_point_send_reply(&r->query_reply);
m->reply_list = rlist;
@@ -1346,7 +1361,7 @@ void mesh_query_done(struct mesh_state* mstate)
}
if(mstate->s.return_rcode == LDNS_RCODE_SERVFAIL ||
(rep && FLAGS_GET_RCODE(rep->flags) == LDNS_RCODE_SERVFAIL)) {
- /* we are SERVFAILing; check for expired asnwer here */
+ /* we are SERVFAILing; check for expired answer here */
mesh_serve_expired_callback(mstate);
if((mstate->reply_list || mstate->cb_list)
&& mstate->s.env->cfg->log_servfail
@@ -1488,12 +1503,15 @@ int mesh_state_add_cb(struct mesh_state* s, struct edns_data* edns,
r->cb = cb;
r->cb_arg = cb_arg;
r->edns = *edns;
- if(edns->opt_list) {
- r->edns.opt_list = edns_opt_copy_region(edns->opt_list,
- s->s.region);
- if(!r->edns.opt_list)
- return 0;
- }
+ if(edns->opt_list_in && !(r->edns.opt_list_in =
+ edns_opt_copy_region(edns->opt_list_in, s->s.region)))
+ return 0;
+ if(edns->opt_list_out && !(r->edns.opt_list_out =
+ edns_opt_copy_region(edns->opt_list_out, s->s.region)))
+ return 0;
+ if(edns->opt_list_inplace_cb_out && !(r->edns.opt_list_inplace_cb_out =
+ edns_opt_copy_region(edns->opt_list_inplace_cb_out, s->s.region)))
+ return 0;
r->qid = qid;
r->qflags = qflags;
r->next = s->cb_list;
@@ -1512,12 +1530,15 @@ int mesh_state_add_reply(struct mesh_state* s, struct edns_data* edns,
return 0;
r->query_reply = *rep;
r->edns = *edns;
- if(edns->opt_list) {
- r->edns.opt_list = edns_opt_copy_region(edns->opt_list,
- s->s.region);
- if(!r->edns.opt_list)
- return 0;
- }
+ if(edns->opt_list_in && !(r->edns.opt_list_in =
+ edns_opt_copy_region(edns->opt_list_in, s->s.region)))
+ return 0;
+ if(edns->opt_list_out && !(r->edns.opt_list_out =
+ edns_opt_copy_region(edns->opt_list_out, s->s.region)))
+ return 0;
+ if(edns->opt_list_inplace_cb_out && !(r->edns.opt_list_inplace_cb_out =
+ edns_opt_copy_region(edns->opt_list_inplace_cb_out, s->s.region)))
+ return 0;
r->qid = qid;
r->qflags = qflags;
r->start_time = *s->s.env->now_tv;
@@ -1563,7 +1584,7 @@ int mesh_state_add_reply(struct mesh_state* s, struct edns_data* edns,
return 0;
/* the rrset is not packed, like in the cache, but it is
- * individualy allocated with an allocator from localzone. */
+ * individually allocated with an allocator from localzone. */
d = regional_alloc_zero(s->s.region, sizeof(*d));
if(!d)
return 0;
diff --git a/contrib/unbound/services/outbound_list.h b/contrib/unbound/services/outbound_list.h
index ad59e42d1929..73c137d50993 100644
--- a/contrib/unbound/services/outbound_list.h
+++ b/contrib/unbound/services/outbound_list.h
@@ -79,7 +79,7 @@ void outbound_list_init(struct outbound_list* list);
* Clear the user owner outbound list structure.
* Deletes serviced queries.
* @param list: the list structure. It is cleared, but the list struct itself
- * is callers responsability to delete.
+ * is callers responsibility to delete.
*/
void outbound_list_clear(struct outbound_list* list);
diff --git a/contrib/unbound/services/outside_network.c b/contrib/unbound/services/outside_network.c
index a3f982e72185..f4a5d0707845 100644
--- a/contrib/unbound/services/outside_network.c
+++ b/contrib/unbound/services/outside_network.c
@@ -1935,7 +1935,7 @@ select_id(struct outside_network* outnet, struct pending* pend,
LDNS_ID_SET(sldns_buffer_begin(packet), pend->id);
id_tries++;
if(id_tries == MAX_ID_RETRY) {
- pend->id=99999; /* non existant ID */
+ pend->id=99999; /* non existent ID */
log_err("failed to generate unique ID, drop msg");
return 0;
}
@@ -1962,6 +1962,7 @@ static int udp_connect_needs_log(int err)
case ENETDOWN:
# endif
case EPERM:
+ case EACCES:
if(verbosity >= VERB_ALGO)
return 1;
return 0;
@@ -2708,7 +2709,9 @@ serviced_encode(struct serviced_query* sq, sldns_buffer* buff, int with_edns)
edns.edns_present = 1;
edns.ext_rcode = 0;
edns.edns_version = EDNS_ADVERTISED_VERSION;
- edns.opt_list = sq->opt_list;
+ edns.opt_list_in = NULL;
+ edns.opt_list_out = sq->opt_list;
+ edns.opt_list_inplace_cb_out = NULL;
if(sq->status == serviced_query_UDP_EDNS_FRAG) {
if(addr_is_ip6(&sq->addr, sq->addrlen)) {
if(EDNS_FRAG_SIZE_IP6 < EDNS_ADVERTISED_SIZE)
@@ -2731,8 +2734,8 @@ serviced_encode(struct serviced_query* sq, sldns_buffer* buff, int with_edns)
padding_option.opt_code = LDNS_EDNS_PADDING;
padding_option.opt_len = 0;
padding_option.opt_data = NULL;
- padding_option.next = edns.opt_list;
- edns.opt_list = &padding_option;
+ padding_option.next = edns.opt_list_out;
+ edns.opt_list_out = &padding_option;
edns.padding_block_size = sq->padding_block_size;
}
attach_edns_record(buff, &edns);
diff --git a/contrib/unbound/services/rpz.c b/contrib/unbound/services/rpz.c
index 3a1ec00d7d38..d408f9383d24 100644
--- a/contrib/unbound/services/rpz.c
+++ b/contrib/unbound/services/rpz.c
@@ -50,45 +50,50 @@
#include "util/data/dname.h"
#include "util/locks.h"
#include "util/regional.h"
+#include "util/data/msgencode.h"
+#include "services/cache/dns.h"
+#include "iterator/iterator.h"
+#include "iterator/iter_delegpt.h"
+#include "daemon/worker.h"
+
+typedef struct resp_addr rpz_aclnode_type;
+
+struct matched_delegation_point {
+ uint8_t* dname;
+ size_t dname_len;
+};
/** string for RPZ action enum */
const char*
rpz_action_to_string(enum rpz_action a)
{
switch(a) {
- case RPZ_NXDOMAIN_ACTION: return "nxdomain";
- case RPZ_NODATA_ACTION: return "nodata";
- case RPZ_PASSTHRU_ACTION: return "passthru";
- case RPZ_DROP_ACTION: return "drop";
- case RPZ_TCP_ONLY_ACTION: return "tcp_only";
- case RPZ_INVALID_ACTION: return "invalid";
- case RPZ_LOCAL_DATA_ACTION: return "local_data";
- case RPZ_DISABLED_ACTION: return "disabled";
- case RPZ_CNAME_OVERRIDE_ACTION: return "cname_override";
- case RPZ_NO_OVERRIDE_ACTION: return "no_override";
+ case RPZ_NXDOMAIN_ACTION: return "rpz-nxdomain";
+ case RPZ_NODATA_ACTION: return "rpz-nodata";
+ case RPZ_PASSTHRU_ACTION: return "rpz-passthru";
+ case RPZ_DROP_ACTION: return "rpz-drop";
+ case RPZ_TCP_ONLY_ACTION: return "rpz-tcp-only";
+ case RPZ_INVALID_ACTION: return "rpz-invalid";
+ case RPZ_LOCAL_DATA_ACTION: return "rpz-local-data";
+ case RPZ_DISABLED_ACTION: return "rpz-disabled";
+ case RPZ_CNAME_OVERRIDE_ACTION: return "rpz-cname-override";
+ case RPZ_NO_OVERRIDE_ACTION: return "rpz-no-override";
+ default: return "rpz-unknown-action";
}
- return "unknown";
}
/** RPZ action enum for config string */
static enum rpz_action
rpz_config_to_action(char* a)
{
- if(strcmp(a, "nxdomain") == 0)
- return RPZ_NXDOMAIN_ACTION;
- else if(strcmp(a, "nodata") == 0)
- return RPZ_NODATA_ACTION;
- else if(strcmp(a, "passthru") == 0)
- return RPZ_PASSTHRU_ACTION;
- else if(strcmp(a, "drop") == 0)
- return RPZ_DROP_ACTION;
- else if(strcmp(a, "tcp_only") == 0)
- return RPZ_TCP_ONLY_ACTION;
- else if(strcmp(a, "cname") == 0)
- return RPZ_CNAME_OVERRIDE_ACTION;
- else if(strcmp(a, "disabled") == 0)
- return RPZ_DISABLED_ACTION;
- return RPZ_INVALID_ACTION;
+ if(strcmp(a, "nxdomain") == 0) return RPZ_NXDOMAIN_ACTION;
+ else if(strcmp(a, "nodata") == 0) return RPZ_NODATA_ACTION;
+ else if(strcmp(a, "passthru") == 0) return RPZ_PASSTHRU_ACTION;
+ else if(strcmp(a, "drop") == 0) return RPZ_DROP_ACTION;
+ else if(strcmp(a, "tcp_only") == 0) return RPZ_TCP_ONLY_ACTION;
+ else if(strcmp(a, "cname") == 0) return RPZ_CNAME_OVERRIDE_ACTION;
+ else if(strcmp(a, "disabled") == 0) return RPZ_DISABLED_ACTION;
+ else return RPZ_INVALID_ACTION;
}
/** string for RPZ trigger enum */
@@ -96,14 +101,14 @@ static const char*
rpz_trigger_to_string(enum rpz_trigger r)
{
switch(r) {
- case RPZ_QNAME_TRIGGER: return "qname";
- case RPZ_CLIENT_IP_TRIGGER: return "client_ip";
- case RPZ_RESPONSE_IP_TRIGGER: return "response_ip";
- case RPZ_NSDNAME_TRIGGER: return "nsdname";
- case RPZ_NSIP_TRIGGER: return "nsip";
- case RPZ_INVALID_TRIGGER: return "invalid";
+ case RPZ_QNAME_TRIGGER: return "rpz-qname";
+ case RPZ_CLIENT_IP_TRIGGER: return "rpz-client-ip";
+ case RPZ_RESPONSE_IP_TRIGGER: return "rpz-response-ip";
+ case RPZ_NSDNAME_TRIGGER: return "rpz-nsdname";
+ case RPZ_NSIP_TRIGGER: return "rpz-nsip";
+ case RPZ_INVALID_TRIGGER: return "rpz-invalid";
+ default: return "rpz-unknown-trigger";
}
- return "unknown";
}
/**
@@ -138,6 +143,31 @@ get_tld_label(uint8_t* dname, size_t maxdnamelen)
}
/**
+ * The RR types that are to be ignored.
+ * DNSSEC RRs at the apex, and SOA and NS are ignored.
+ */
+static int
+rpz_type_ignored(uint16_t rr_type)
+{
+ switch(rr_type) {
+ case LDNS_RR_TYPE_SOA:
+ case LDNS_RR_TYPE_NS:
+ case LDNS_RR_TYPE_DNAME:
+ /* all DNSSEC-related RRs must be ignored */
+ case LDNS_RR_TYPE_DNSKEY:
+ case LDNS_RR_TYPE_DS:
+ case LDNS_RR_TYPE_RRSIG:
+ case LDNS_RR_TYPE_NSEC:
+ case LDNS_RR_TYPE_NSEC3:
+ case LDNS_RR_TYPE_NSEC3PARAM:
+ return 1;
+ default:
+ break;
+ }
+ return 0;
+}
+
+/**
* Classify RPZ action for RR type/rdata
* @param rr_type: the RR type
* @param rdatawl: RDATA with 2 bytes length
@@ -208,15 +238,15 @@ static enum localzone_type
rpz_action_to_localzone_type(enum rpz_action a)
{
switch(a) {
- case RPZ_NXDOMAIN_ACTION: return local_zone_always_nxdomain;
- case RPZ_NODATA_ACTION: return local_zone_always_nodata;
- case RPZ_DROP_ACTION: return local_zone_always_deny;
- case RPZ_PASSTHRU_ACTION: return local_zone_always_transparent;
+ case RPZ_NXDOMAIN_ACTION: return local_zone_always_nxdomain;
+ case RPZ_NODATA_ACTION: return local_zone_always_nodata;
+ case RPZ_DROP_ACTION: return local_zone_always_deny;
+ case RPZ_PASSTHRU_ACTION: return local_zone_always_transparent;
case RPZ_LOCAL_DATA_ACTION: /* fallthrough */
case RPZ_CNAME_OVERRIDE_ACTION: return local_zone_redirect;
- case RPZ_INVALID_ACTION: /* fallthrough */
- case RPZ_TCP_ONLY_ACTION: /* fallthrough */
- default: return local_zone_invalid;
+ case RPZ_TCP_ONLY_ACTION: return local_zone_truncate;
+ case RPZ_INVALID_ACTION: /* fallthrough */
+ default: return local_zone_invalid;
}
}
@@ -224,15 +254,15 @@ enum respip_action
rpz_action_to_respip_action(enum rpz_action a)
{
switch(a) {
- case RPZ_NXDOMAIN_ACTION: return respip_always_nxdomain;
- case RPZ_NODATA_ACTION: return respip_always_nodata;
- case RPZ_DROP_ACTION: return respip_always_deny;
- case RPZ_PASSTHRU_ACTION: return respip_always_transparent;
- case RPZ_LOCAL_DATA_ACTION: /* fallthrough */
+ case RPZ_NXDOMAIN_ACTION: return respip_always_nxdomain;
+ case RPZ_NODATA_ACTION: return respip_always_nodata;
+ case RPZ_DROP_ACTION: return respip_always_deny;
+ case RPZ_PASSTHRU_ACTION: return respip_always_transparent;
+ case RPZ_LOCAL_DATA_ACTION: /* fallthrough */
case RPZ_CNAME_OVERRIDE_ACTION: return respip_redirect;
- case RPZ_INVALID_ACTION: /* fallthrough */
- case RPZ_TCP_ONLY_ACTION: /* fallthrough */
- default: return respip_invalid;
+ case RPZ_TCP_ONLY_ACTION: return respip_truncate;
+ case RPZ_INVALID_ACTION: /* fallthrough */
+ default: return respip_invalid;
}
}
@@ -240,14 +270,14 @@ static enum rpz_action
localzone_type_to_rpz_action(enum localzone_type lzt)
{
switch(lzt) {
- case local_zone_always_nxdomain: return RPZ_NXDOMAIN_ACTION;
- case local_zone_always_nodata: return RPZ_NODATA_ACTION;
- case local_zone_always_deny: return RPZ_DROP_ACTION;
- case local_zone_always_transparent: return RPZ_PASSTHRU_ACTION;
- case local_zone_redirect: return RPZ_LOCAL_DATA_ACTION;
- case local_zone_invalid:
- default:
- return RPZ_INVALID_ACTION;
+ case local_zone_always_nxdomain: return RPZ_NXDOMAIN_ACTION;
+ case local_zone_always_nodata: return RPZ_NODATA_ACTION;
+ case local_zone_always_deny: return RPZ_DROP_ACTION;
+ case local_zone_always_transparent: return RPZ_PASSTHRU_ACTION;
+ case local_zone_redirect: return RPZ_LOCAL_DATA_ACTION;
+ case local_zone_truncate: return RPZ_TCP_ONLY_ACTION;
+ case local_zone_invalid: /* fallthrough */
+ default: return RPZ_INVALID_ACTION;
}
}
@@ -255,14 +285,14 @@ enum rpz_action
respip_action_to_rpz_action(enum respip_action a)
{
switch(a) {
- case respip_always_nxdomain: return RPZ_NXDOMAIN_ACTION;
- case respip_always_nodata: return RPZ_NODATA_ACTION;
- case respip_always_deny: return RPZ_DROP_ACTION;
- case respip_always_transparent: return RPZ_PASSTHRU_ACTION;
- case respip_redirect: return RPZ_LOCAL_DATA_ACTION;
- case respip_invalid:
- default:
- return RPZ_INVALID_ACTION;
+ case respip_always_nxdomain: return RPZ_NXDOMAIN_ACTION;
+ case respip_always_nodata: return RPZ_NODATA_ACTION;
+ case respip_always_deny: return RPZ_DROP_ACTION;
+ case respip_always_transparent: return RPZ_PASSTHRU_ACTION;
+ case respip_redirect: return RPZ_LOCAL_DATA_ACTION;
+ case respip_truncate: return RPZ_TCP_ONLY_ACTION;
+ case respip_invalid: /* fallthrough */
+ default: return RPZ_INVALID_ACTION;
}
}
@@ -298,12 +328,55 @@ rpz_dname_to_trigger(uint8_t* dname, size_t dname_len)
return RPZ_QNAME_TRIGGER;
}
-void rpz_delete(struct rpz* r)
+static inline struct clientip_synthesized_rrset*
+rpz_clientip_synthesized_set_create(void)
+{
+ struct clientip_synthesized_rrset* set = calloc(1, sizeof(*set));
+ if(set == NULL) {
+ return NULL;
+ }
+ set->region = regional_create();
+ if(set->region == NULL) {
+ free(set);
+ return NULL;
+ }
+ addr_tree_init(&set->entries);
+ lock_rw_init(&set->lock);
+ return set;
+}
+
+static void
+rpz_clientip_synthesized_rr_delete(rbnode_type* n, void* ATTR_UNUSED(arg))
+{
+ struct clientip_synthesized_rr* r = (struct clientip_synthesized_rr*)n->key;
+ lock_rw_destroy(&r->lock);
+#ifdef THREADS_DISABLED
+ (void)r;
+#endif
+}
+
+static inline void
+rpz_clientip_synthesized_set_delete(struct clientip_synthesized_rrset* set)
+{
+ if(set == NULL) {
+ return;
+ }
+ lock_rw_destroy(&set->lock);
+ traverse_postorder(&set->entries, rpz_clientip_synthesized_rr_delete, NULL);
+ regional_destroy(set->region);
+ free(set);
+}
+
+void
+rpz_delete(struct rpz* r)
{
if(!r)
return;
local_zones_delete(r->local_zones);
+ local_zones_delete(r->nsdname_zones);
respip_set_delete(r->respip_set);
+ rpz_clientip_synthesized_set_delete(r->client_set);
+ rpz_clientip_synthesized_set_delete(r->ns_set);
regional_destroy(r->region);
free(r->taglist);
free(r->log_name);
@@ -315,13 +388,31 @@ rpz_clear(struct rpz* r)
{
/* must hold write lock on auth_zone */
local_zones_delete(r->local_zones);
+ r->local_zones = NULL;
+ local_zones_delete(r->nsdname_zones);
+ r->nsdname_zones = NULL;
respip_set_delete(r->respip_set);
+ r->respip_set = NULL;
+ rpz_clientip_synthesized_set_delete(r->client_set);
+ r->client_set = NULL;
+ rpz_clientip_synthesized_set_delete(r->ns_set);
+ r->ns_set = NULL;
if(!(r->local_zones = local_zones_create())){
return 0;
}
+ r->nsdname_zones = local_zones_create();
+ if(r->nsdname_zones == NULL) {
+ return 0;
+ }
if(!(r->respip_set = respip_set_create())) {
return 0;
}
+ if(!(r->client_set = rpz_clientip_synthesized_set_create())) {
+ return 0;
+ }
+ if(!(r->ns_set = rpz_clientip_synthesized_set_create())) {
+ return 0;
+ }
return 1;
}
@@ -331,6 +422,14 @@ rpz_finish_config(struct rpz* r)
lock_rw_wrlock(&r->respip_set->lock);
addr_tree_init_parents(&r->respip_set->ip_tree);
lock_rw_unlock(&r->respip_set->lock);
+
+ lock_rw_wrlock(&r->client_set->lock);
+ addr_tree_init_parents(&r->client_set->entries);
+ lock_rw_unlock(&r->client_set->lock);
+
+ lock_rw_wrlock(&r->ns_set->lock);
+ addr_tree_init_parents(&r->ns_set->entries);
+ lock_rw_unlock(&r->ns_set->lock);
}
/** new rrset containing CNAME override, does not yet contain a dname */
@@ -394,9 +493,26 @@ rpz_create(struct config_auth* p)
if(!(r->local_zones = local_zones_create())){
goto err;
}
+
+ r->nsdname_zones = local_zones_create();
+ if(r->local_zones == NULL){
+ goto err;
+ }
+
if(!(r->respip_set = respip_set_create())) {
goto err;
}
+
+ r->client_set = rpz_clientip_synthesized_set_create();
+ if(r->client_set == NULL) {
+ goto err;
+ }
+
+ r->ns_set = rpz_clientip_synthesized_set_create();
+ if(r->ns_set == NULL) {
+ goto err;
+ }
+
r->taglistlen = p->rpz_taglistlen;
r->taglist = memdup(p->rpz_taglist, r->taglistlen);
if(p->rpz_action_override) {
@@ -437,8 +553,14 @@ err:
if(r) {
if(r->local_zones)
local_zones_delete(r->local_zones);
+ if(r->nsdname_zones)
+ local_zones_delete(r->nsdname_zones);
if(r->respip_set)
respip_set_delete(r->respip_set);
+ if(r->client_set != NULL)
+ rpz_clientip_synthesized_set_delete(r->client_set);
+ if(r->ns_set != NULL)
+ rpz_clientip_synthesized_set_delete(r->ns_set);
if(r->taglist)
free(r->taglist);
if(r->region)
@@ -467,19 +589,17 @@ strip_dname_origin(uint8_t* dname, size_t dnamelen, size_t originlen,
return newdnamelen + 1; /* + 1 for root label */
}
-/** Insert RR into RPZ's local-zone */
static void
-rpz_insert_qname_trigger(struct rpz* r, uint8_t* dname, size_t dnamelen,
- enum rpz_action a, uint16_t rrtype, uint16_t rrclass, uint32_t ttl,
- uint8_t* rdata, size_t rdata_len, uint8_t* rr, size_t rr_len)
+rpz_insert_local_zones_trigger(struct local_zones* lz, uint8_t* dname,
+ size_t dnamelen, enum rpz_action a, uint16_t rrtype, uint16_t rrclass,
+ uint32_t ttl, uint8_t* rdata, size_t rdata_len, uint8_t* rr, size_t rr_len)
{
struct local_zone* z;
enum localzone_type tp = local_zone_always_transparent;
int dnamelabs = dname_count_labels(dname);
- char* rrstr;
int newzone = 0;
- if(a == RPZ_TCP_ONLY_ACTION || a == RPZ_INVALID_ACTION) {
+ if(a == RPZ_INVALID_ACTION) {
char str[255+1];
if(rrtype == LDNS_RR_TYPE_SOA || rrtype == LDNS_RR_TYPE_NS ||
rrtype == LDNS_RR_TYPE_DNAME ||
@@ -499,110 +619,394 @@ rpz_insert_qname_trigger(struct rpz* r, uint8_t* dname, size_t dnamelen,
return;
}
- lock_rw_wrlock(&r->local_zones->lock);
+ lock_rw_wrlock(&lz->lock);
/* exact match */
- z = local_zones_find(r->local_zones, dname, dnamelen, dnamelabs,
- LDNS_RR_CLASS_IN);
- if(z && a != RPZ_LOCAL_DATA_ACTION) {
- rrstr = sldns_wire2str_rr(rr, rr_len);
- if(!rrstr) {
- log_err("malloc error while inserting RPZ qname "
- "trigger");
+ z = local_zones_find(lz, dname, dnamelen, dnamelabs, LDNS_RR_CLASS_IN);
+ if(z != NULL && a != RPZ_LOCAL_DATA_ACTION) {
+ char* rrstr = sldns_wire2str_rr(rr, rr_len);
+ if(rrstr == NULL) {
+ log_err("malloc error while inserting rpz nsdname trigger");
free(dname);
- lock_rw_unlock(&r->local_zones->lock);
+ lock_rw_unlock(&lz->lock);
return;
}
- verbose(VERB_ALGO, "RPZ: skipping duplicate record: '%s'",
- rrstr);
+ if(rrstr[0])
+ rrstr[strlen(rrstr)-1]=0; /* remove newline */
+ verbose(VERB_ALGO, "rpz: skipping duplicate record: '%s'", rrstr);
free(rrstr);
free(dname);
- lock_rw_unlock(&r->local_zones->lock);
+ lock_rw_unlock(&lz->lock);
return;
}
- if(!z) {
+ if(z == NULL) {
tp = rpz_action_to_localzone_type(a);
- if(!(z = local_zones_add_zone(r->local_zones, dname, dnamelen,
- dnamelabs, rrclass, tp))) {
- log_warn("RPZ create failed");
- lock_rw_unlock(&r->local_zones->lock);
+ z = local_zones_add_zone(lz, dname, dnamelen,
+ dnamelabs, rrclass, tp);
+ if(z == NULL) {
+ log_warn("rpz: create failed");
+ lock_rw_unlock(&lz->lock);
/* dname will be free'd in failed local_zone_create() */
return;
}
newzone = 1;
}
if(a == RPZ_LOCAL_DATA_ACTION) {
- rrstr = sldns_wire2str_rr(rr, rr_len);
- if(!rrstr) {
- log_err("malloc error while inserting RPZ qname "
- "trigger");
+ char* rrstr = sldns_wire2str_rr(rr, rr_len);
+ if(rrstr == NULL) {
+ log_err("malloc error while inserting rpz nsdname trigger");
free(dname);
- lock_rw_unlock(&r->local_zones->lock);
+ lock_rw_unlock(&lz->lock);
return;
}
lock_rw_wrlock(&z->lock);
- local_zone_enter_rr(z, dname, dnamelen, dnamelabs,
- rrtype, rrclass, ttl, rdata, rdata_len, rrstr);
+ local_zone_enter_rr(z, dname, dnamelen, dnamelabs, rrtype,
+ rrclass, ttl, rdata, rdata_len, rrstr);
lock_rw_unlock(&z->lock);
free(rrstr);
}
- if(!newzone)
+ if(!newzone) {
free(dname);
- lock_rw_unlock(&r->local_zones->lock);
- return;
+ }
+ lock_rw_unlock(&lz->lock);
+}
+
+static void
+rpz_log_dname(char const* msg, uint8_t* dname, size_t dname_len)
+{
+ char buf[LDNS_MAX_DOMAINLEN+1];
+ (void)dname_len;
+ dname_str(dname, buf);
+ verbose(VERB_ALGO, "rpz: %s: <%s>", msg, buf);
+}
+
+static void
+rpz_insert_qname_trigger(struct rpz* r, uint8_t* dname, size_t dnamelen,
+ enum rpz_action a, uint16_t rrtype, uint16_t rrclass, uint32_t ttl,
+ uint8_t* rdata, size_t rdata_len, uint8_t* rr, size_t rr_len)
+{
+ if(a == RPZ_INVALID_ACTION) {
+ verbose(VERB_ALGO, "rpz: skipping invalid action");
+ free(dname);
+ return;
+ }
+
+ rpz_insert_local_zones_trigger(r->local_zones, dname, dnamelen, a, rrtype,
+ rrclass, ttl, rdata, rdata_len, rr, rr_len);
}
-/** Insert RR into RPZ's respip_set */
static int
-rpz_insert_response_ip_trigger(struct rpz* r, uint8_t* dname, size_t dnamelen,
+rpz_strip_nsdname_suffix(uint8_t* dname, size_t maxdnamelen,
+ uint8_t** stripdname, size_t* stripdnamelen)
+{
+ uint8_t* tldstart = get_tld_label(dname, maxdnamelen);
+ uint8_t swap;
+ if(tldstart == NULL) {
+ if(dname == NULL) {
+ *stripdname = NULL;
+ *stripdnamelen = 0;
+ return 0;
+ }
+ *stripdname = memdup(dname, maxdnamelen);
+ if(!*stripdname) {
+ *stripdnamelen = 0;
+ log_err("malloc failure for rpz strip suffix");
+ return 0;
+ }
+ *stripdnamelen = maxdnamelen;
+ return 1;
+ }
+ /* shorten the domain name briefly,
+ * then we allocate a new name with the correct length */
+ swap = *tldstart;
+ *tldstart = 0;
+ (void)dname_count_size_labels(dname, stripdnamelen);
+ *stripdname = memdup(dname, *stripdnamelen);
+ *tldstart = swap;
+ if(!*stripdname) {
+ *stripdnamelen = 0;
+ log_err("malloc failure for rpz strip suffix");
+ return 0;
+ }
+ return 1;
+}
+
+static void
+rpz_insert_nsdname_trigger(struct rpz* r, uint8_t* dname, size_t dnamelen,
enum rpz_action a, uint16_t rrtype, uint16_t rrclass, uint32_t ttl,
uint8_t* rdata, size_t rdata_len, uint8_t* rr, size_t rr_len)
{
+ uint8_t* dname_stripped = NULL;
+ size_t dnamelen_stripped = 0;
+
+ rpz_strip_nsdname_suffix(dname, dnamelen, &dname_stripped,
+ &dnamelen_stripped);
+ if(a == RPZ_INVALID_ACTION) {
+ verbose(VERB_ALGO, "rpz: skipping invalid action");
+ free(dname_stripped);
+ return;
+ }
+
+ /* dname_stripped is consumed or freed by the insert routine */
+ rpz_insert_local_zones_trigger(r->nsdname_zones, dname_stripped,
+ dnamelen_stripped, a, rrtype, rrclass, ttl, rdata, rdata_len,
+ rr, rr_len);
+}
+
+static int
+rpz_insert_ipaddr_based_trigger(struct respip_set* set, struct sockaddr_storage* addr,
+ socklen_t addrlen, int net, enum rpz_action a, uint16_t rrtype,
+ uint16_t rrclass, uint32_t ttl, uint8_t* rdata, size_t rdata_len,
+ uint8_t* rr, size_t rr_len)
+{
struct resp_addr* node;
- struct sockaddr_storage addr;
- socklen_t addrlen;
- int net, af;
char* rrstr;
enum respip_action respa = rpz_action_to_respip_action(a);
- if(a == RPZ_TCP_ONLY_ACTION || a == RPZ_INVALID_ACTION ||
- respa == respip_invalid) {
- char str[255+1];
- dname_str(dname, str);
- verbose(VERB_ALGO, "RPZ: respip trigger, %s skipping unsupported action: %s",
- str, rpz_action_to_string(a));
+ lock_rw_wrlock(&set->lock);
+ rrstr = sldns_wire2str_rr(rr, rr_len);
+ if(rrstr == NULL) {
+ log_err("malloc error while inserting rpz ipaddr based trigger");
+ lock_rw_unlock(&set->lock);
return 0;
}
- if(!netblockdnametoaddr(dname, dnamelen, &addr, &addrlen, &net, &af))
+ node = respip_sockaddr_find_or_create(set, addr, addrlen, net, 1, rrstr);
+ if(node == NULL) {
+ lock_rw_unlock(&set->lock);
+ free(rrstr);
return 0;
+ }
- lock_rw_wrlock(&r->respip_set->lock);
- rrstr = sldns_wire2str_rr(rr, rr_len);
- if(!rrstr) {
- log_err("malloc error while inserting RPZ respip trigger");
- lock_rw_unlock(&r->respip_set->lock);
+ lock_rw_wrlock(&node->lock);
+ lock_rw_unlock(&set->lock);
+
+ node->action = respa;
+
+ if(a == RPZ_LOCAL_DATA_ACTION) {
+ respip_enter_rr(set->region, node, rrtype,
+ rrclass, ttl, rdata, rdata_len, rrstr, "");
+ }
+
+ lock_rw_unlock(&node->lock);
+ free(rrstr);
+ return 1;
+}
+
+static inline struct clientip_synthesized_rr*
+rpz_clientip_ensure_entry(struct clientip_synthesized_rrset* set,
+ struct sockaddr_storage* addr, socklen_t addrlen, int net)
+{
+ int insert_ok;
+ struct clientip_synthesized_rr* node =
+ (struct clientip_synthesized_rr*)addr_tree_find(&set->entries,
+ addr, addrlen, net);
+
+ if(node != NULL) { return node; }
+
+ /* node does not yet exist => allocate one */
+ node = regional_alloc_zero(set->region, sizeof(*node));
+ if(node == NULL) {
+ log_err("out of memory");
+ return NULL;
+ }
+
+ lock_rw_init(&node->lock);
+ node->action = RPZ_INVALID_ACTION;
+ insert_ok = addr_tree_insert(&set->entries, &node->node,
+ addr, addrlen, net);
+ if (!insert_ok) {
+ log_warn("rpz: unexpected: unable to insert clientip address node");
+ /* we can not free the just allocated node.
+ * theoretically a memleak */
+ return NULL;
+ }
+
+ return node;
+}
+
+static void
+rpz_report_rrset_error(const char* msg, uint8_t* rr, size_t rr_len) {
+ char* rrstr = sldns_wire2str_rr(rr, rr_len);
+ if(rrstr == NULL) {
+ log_err("malloc error while inserting rpz clientip based record");
+ return;
+ }
+ log_err("rpz: unexpected: unable to insert %s: %s", msg, rrstr);
+ free(rrstr);
+}
+
+/* from localzone.c; difference is we don't have a dname */
+struct local_rrset*
+rpz_clientip_new_rrset(struct regional* region,
+ struct clientip_synthesized_rr* raddr, uint16_t rrtype, uint16_t rrclass)
+{
+ struct packed_rrset_data* pd;
+ struct local_rrset* rrset = (struct local_rrset*)
+ regional_alloc_zero(region, sizeof(*rrset));
+ if(rrset == NULL) {
+ log_err("out of memory");
+ return NULL;
+ }
+ rrset->next = raddr->data;
+ raddr->data = rrset;
+ rrset->rrset = (struct ub_packed_rrset_key*)
+ regional_alloc_zero(region, sizeof(*rrset->rrset));
+ if(rrset->rrset == NULL) {
+ log_err("out of memory");
+ return NULL;
+ }
+ rrset->rrset->entry.key = rrset->rrset;
+ pd = (struct packed_rrset_data*)regional_alloc_zero(region, sizeof(*pd));
+ if(pd == NULL) {
+ log_err("out of memory");
+ return NULL;
+ }
+ pd->trust = rrset_trust_prim_noglue;
+ pd->security = sec_status_insecure;
+ rrset->rrset->entry.data = pd;
+ rrset->rrset->rk.type = htons(rrtype);
+ rrset->rrset->rk.rrset_class = htons(rrclass);
+ rrset->rrset->rk.dname = regional_alloc_zero(region, 1);
+ if(rrset->rrset->rk.dname == NULL) {
+ log_err("out of memory");
+ return NULL;
+ }
+ rrset->rrset->rk.dname_len = 1;
+ return rrset;
+}
+
+static int
+rpz_clientip_enter_rr(struct regional* region, struct clientip_synthesized_rr* raddr,
+ uint16_t rrtype, uint16_t rrclass, time_t ttl, uint8_t* rdata,
+ size_t rdata_len)
+{
+ struct local_rrset* rrset;
+ if (rrtype == LDNS_RR_TYPE_CNAME && raddr->data != NULL) {
+ log_err("CNAME response-ip data can not co-exist with other "
+ "client-ip data");
return 0;
}
- if(!(node=respip_sockaddr_find_or_create(r->respip_set, &addr, addrlen,
- net, 1, rrstr))) {
- lock_rw_unlock(&r->respip_set->lock);
- free(rrstr);
+
+ rrset = rpz_clientip_new_rrset(region, raddr, rrtype, rrclass);
+ if(raddr->data == NULL) {
+ return 0;
+ }
+
+ return rrset_insert_rr(region, rrset->rrset->entry.data, rdata, rdata_len, ttl, "");
+}
+
+static int
+rpz_clientip_insert_trigger_rr(struct clientip_synthesized_rrset* set, struct sockaddr_storage* addr,
+ socklen_t addrlen, int net, enum rpz_action a, uint16_t rrtype,
+ uint16_t rrclass, uint32_t ttl, uint8_t* rdata, size_t rdata_len,
+ uint8_t* rr, size_t rr_len)
+{
+ struct clientip_synthesized_rr* node;
+
+ lock_rw_wrlock(&set->lock);
+
+ node = rpz_clientip_ensure_entry(set, addr, addrlen, net);
+ if(node == NULL) {
+ lock_rw_unlock(&set->lock);
+ rpz_report_rrset_error("client ip address", rr, rr_len);
return 0;
}
lock_rw_wrlock(&node->lock);
- lock_rw_unlock(&r->respip_set->lock);
- node->action = respa;
+ lock_rw_unlock(&set->lock);
+ node->action = a;
if(a == RPZ_LOCAL_DATA_ACTION) {
- respip_enter_rr(r->respip_set->region, node, rrtype,
- rrclass, ttl, rdata, rdata_len, rrstr, "");
+ if(!rpz_clientip_enter_rr(set->region, node, rrtype,
+ rrclass, ttl, rdata, rdata_len)) {
+ verbose(VERB_ALGO, "rpz: unable to insert clientip rr");
+ lock_rw_unlock(&node->lock);
+ return 0;
+ }
+
}
+
lock_rw_unlock(&node->lock);
- free(rrstr);
+
return 1;
}
+static int
+rpz_insert_clientip_trigger(struct rpz* r, uint8_t* dname, size_t dnamelen,
+ enum rpz_action a, uint16_t rrtype, uint16_t rrclass, uint32_t ttl,
+ uint8_t* rdata, size_t rdata_len, uint8_t* rr, size_t rr_len)
+{
+ struct sockaddr_storage addr;
+ socklen_t addrlen;
+ int net, af;
+
+ if(a == RPZ_INVALID_ACTION) {
+ return 0;
+ }
+
+ if(!netblockdnametoaddr(dname, dnamelen, &addr, &addrlen, &net, &af)) {
+ verbose(VERB_ALGO, "rpz: unable to parse client ip");
+ return 0;
+ }
+
+ return rpz_clientip_insert_trigger_rr(r->client_set, &addr, addrlen, net,
+ a, rrtype, rrclass, ttl, rdata, rdata_len, rr, rr_len);
+}
+
+static int
+rpz_insert_nsip_trigger(struct rpz* r, uint8_t* dname, size_t dnamelen,
+ enum rpz_action a, uint16_t rrtype, uint16_t rrclass, uint32_t ttl,
+ uint8_t* rdata, size_t rdata_len, uint8_t* rr, size_t rr_len)
+{
+ struct sockaddr_storage addr;
+ socklen_t addrlen;
+ int net, af;
+
+ if(a == RPZ_INVALID_ACTION) {
+ return 0;
+ }
+
+ if(!netblockdnametoaddr(dname, dnamelen, &addr, &addrlen, &net, &af)) {
+ verbose(VERB_ALGO, "rpz: unable to parse ns ip");
+ return 0;
+ }
+
+ return rpz_clientip_insert_trigger_rr(r->ns_set, &addr, addrlen, net,
+ a, rrtype, rrclass, ttl, rdata, rdata_len, rr, rr_len);
+}
+
+/** Insert RR into RPZ's respip_set */
+static int
+rpz_insert_response_ip_trigger(struct rpz* r, uint8_t* dname, size_t dnamelen,
+ enum rpz_action a, uint16_t rrtype, uint16_t rrclass, uint32_t ttl,
+ uint8_t* rdata, size_t rdata_len, uint8_t* rr, size_t rr_len)
+{
+ struct sockaddr_storage addr;
+ socklen_t addrlen;
+ int net, af;
+
+ if(a == RPZ_INVALID_ACTION) {
+ return 0;
+ }
+
+ if(!netblockdnametoaddr(dname, dnamelen, &addr, &addrlen, &net, &af)) {
+ verbose(VERB_ALGO, "rpz: unable to parse response ip");
+ return 0;
+ }
+
+ if(a == RPZ_INVALID_ACTION ||
+ rpz_action_to_respip_action(a) == respip_invalid) {
+ char str[255+1];
+ dname_str(dname, str);
+ verbose(VERB_ALGO, "RPZ: respip trigger, %s skipping unsupported action: %s",
+ str, rpz_action_to_string(a));
+ return 0;
+ }
+
+ return rpz_insert_ipaddr_based_trigger(r->respip_set, &addr, addrlen, net,
+ a, rrtype, rrclass, ttl, rdata, rdata_len, rr, rr_len);
+}
+
int
rpz_insert_rr(struct rpz* r, uint8_t* azname, size_t aznamelen, uint8_t* dname,
size_t dnamelen, uint16_t rr_type, uint16_t rr_class, uint32_t rr_ttl,
@@ -614,15 +1018,19 @@ rpz_insert_rr(struct rpz* r, uint8_t* azname, size_t aznamelen, uint8_t* dname,
enum rpz_action a;
uint8_t* policydname;
+ if(rpz_type_ignored(rr_type)) {
+ /* this rpz action is not valid, eg. this is the SOA or NS RR */
+ return 1;
+ }
if(!dname_subdomain_c(dname, azname)) {
char* dname_str = sldns_wire2str_dname(dname, dnamelen);
char* azname_str = sldns_wire2str_dname(azname, aznamelen);
if(dname_str && azname_str) {
- log_err("RPZ: name of record (%s) to insert into RPZ is not a "
+ log_err("rpz: name of record (%s) to insert into RPZ is not a "
"subdomain of the configured name of the RPZ zone (%s)",
dname_str, azname_str);
} else {
- log_err("RPZ: name of record to insert into RPZ is not a "
+ log_err("rpz: name of record to insert into RPZ is not a "
"subdomain of the configured name of the RPZ zone");
}
free(dname_str);
@@ -645,23 +1053,37 @@ rpz_insert_rr(struct rpz* r, uint8_t* azname, size_t aznamelen, uint8_t* dname,
t = rpz_dname_to_trigger(policydname, policydnamelen);
if(t == RPZ_INVALID_TRIGGER) {
free(policydname);
- verbose(VERB_ALGO, "RPZ: skipping invalid trigger");
+ verbose(VERB_ALGO, "rpz: skipping invalid trigger");
return 1;
}
if(t == RPZ_QNAME_TRIGGER) {
+ /* policydname will be consumed, no free */
rpz_insert_qname_trigger(r, policydname, policydnamelen,
a, rr_type, rr_class, rr_ttl, rdatawl, rdatalen, rr,
rr_len);
- }
- else if(t == RPZ_RESPONSE_IP_TRIGGER) {
+ } else if(t == RPZ_RESPONSE_IP_TRIGGER) {
rpz_insert_response_ip_trigger(r, policydname, policydnamelen,
a, rr_type, rr_class, rr_ttl, rdatawl, rdatalen, rr,
rr_len);
free(policydname);
- }
- else {
+ } else if(t == RPZ_CLIENT_IP_TRIGGER) {
+ rpz_insert_clientip_trigger(r, policydname, policydnamelen,
+ a, rr_type, rr_class, rr_ttl, rdatawl, rdatalen, rr,
+ rr_len);
+ free(policydname);
+ } else if(t == RPZ_NSIP_TRIGGER) {
+ rpz_insert_nsip_trigger(r, policydname, policydnamelen,
+ a, rr_type, rr_class, rr_ttl, rdatawl, rdatalen, rr,
+ rr_len);
+ free(policydname);
+ } else if(t == RPZ_NSDNAME_TRIGGER) {
+ rpz_insert_nsdname_trigger(r, policydname, policydnamelen,
+ a, rr_type, rr_class, rr_ttl, rdatawl, rdatalen, rr,
+ rr_len);
free(policydname);
- verbose(VERB_ALGO, "RPZ: skipping unsupported trigger: %s",
+ } else {
+ free(policydname);
+ verbose(VERB_ALGO, "rpz: skipping unsupported trigger: %s",
rpz_trigger_to_string(t));
}
return 1;
@@ -669,18 +1091,18 @@ rpz_insert_rr(struct rpz* r, uint8_t* azname, size_t aznamelen, uint8_t* dname,
/**
* Find RPZ local-zone by qname.
- * @param r: rpz containing local-zone tree
+ * @param zones: local-zone tree
* @param qname: qname
* @param qname_len: length of qname
* @param qclass: qclass
- * @param only_exact: if 1 only excact (non wildcard) matches are returned
+ * @param only_exact: if 1 only exact (non wildcard) matches are returned
* @param wr: get write lock for local-zone if 1, read lock if 0
* @param zones_keep_lock: if set do not release the r->local_zones lock, this
* makes the caller of this function responsible for releasing the lock.
* @return: NULL or local-zone holding rd or wr lock
*/
static struct local_zone*
-rpz_find_zone(struct rpz* r, uint8_t* qname, size_t qname_len, uint16_t qclass,
+rpz_find_zone(struct local_zones* zones, uint8_t* qname, size_t qname_len, uint16_t qclass,
int only_exact, int wr, int zones_keep_lock)
{
uint8_t* ce;
@@ -689,16 +1111,19 @@ rpz_find_zone(struct rpz* r, uint8_t* qname, size_t qname_len, uint16_t qclass,
uint8_t wc[LDNS_MAX_DOMAINLEN+1];
int exact;
struct local_zone* z = NULL;
+
if(wr) {
- lock_rw_wrlock(&r->local_zones->lock);
+ lock_rw_wrlock(&zones->lock);
} else {
- lock_rw_rdlock(&r->local_zones->lock);
+ lock_rw_rdlock(&zones->lock);
}
- z = local_zones_find_le(r->local_zones, qname, qname_len,
+ z = local_zones_find_le(zones, qname, qname_len,
dname_count_labels(qname),
LDNS_RR_CLASS_IN, &exact);
if(!z || (only_exact && !exact)) {
- lock_rw_unlock(&r->local_zones->lock);
+ if(!zones_keep_lock) {
+ lock_rw_unlock(&zones->lock);
+ }
return NULL;
}
if(wr) {
@@ -707,7 +1132,7 @@ rpz_find_zone(struct rpz* r, uint8_t* qname, size_t qname_len, uint16_t qclass,
lock_rw_rdlock(&z->lock);
}
if(!zones_keep_lock) {
- lock_rw_unlock(&r->local_zones->lock);
+ lock_rw_unlock(&zones->lock);
}
if(exact)
@@ -721,7 +1146,7 @@ rpz_find_zone(struct rpz* r, uint8_t* qname, size_t qname_len, uint16_t qclass,
if(!ce /* should not happen */) {
lock_rw_unlock(&z->lock);
if(zones_keep_lock) {
- lock_rw_unlock(&r->local_zones->lock);
+ lock_rw_unlock(&zones->lock);
}
return NULL;
}
@@ -729,7 +1154,7 @@ rpz_find_zone(struct rpz* r, uint8_t* qname, size_t qname_len, uint16_t qclass,
if(ce_len+2 > sizeof(wc)) {
lock_rw_unlock(&z->lock);
if(zones_keep_lock) {
- lock_rw_unlock(&r->local_zones->lock);
+ lock_rw_unlock(&zones->lock);
}
return NULL;
}
@@ -740,15 +1165,15 @@ rpz_find_zone(struct rpz* r, uint8_t* qname, size_t qname_len, uint16_t qclass,
if(!zones_keep_lock) {
if(wr) {
- lock_rw_wrlock(&r->local_zones->lock);
+ lock_rw_wrlock(&zones->lock);
} else {
- lock_rw_rdlock(&r->local_zones->lock);
+ lock_rw_rdlock(&zones->lock);
}
}
- z = local_zones_find_le(r->local_zones, wc,
+ z = local_zones_find_le(zones, wc,
ce_len+2, ce_labs+1, qclass, &exact);
if(!z || !exact) {
- lock_rw_unlock(&r->local_zones->lock);
+ lock_rw_unlock(&zones->lock);
return NULL;
}
if(wr) {
@@ -757,7 +1182,7 @@ rpz_find_zone(struct rpz* r, uint8_t* qname, size_t qname_len, uint16_t qclass,
lock_rw_rdlock(&z->lock);
}
if(!zones_keep_lock) {
- lock_rw_unlock(&r->local_zones->lock);
+ lock_rw_unlock(&zones->lock);
}
return z;
}
@@ -766,7 +1191,7 @@ rpz_find_zone(struct rpz* r, uint8_t* qname, size_t qname_len, uint16_t qclass,
* Remove RR from RPZ's local-data
* @param z: local-zone for RPZ, holding write lock
* @param policydname: dname of RR to remove
- * @param policydnamelen: lenth of policydname
+ * @param policydnamelen: length of policydname
* @param rr_type: RR type of RR to remove
* @param rdata: rdata of RR to remove
* @param rdatalen: length of rdata
@@ -852,10 +1277,10 @@ rpz_remove_qname_trigger(struct rpz* r, uint8_t* dname, size_t dnamelen,
{
struct local_zone* z;
int delete_zone = 1;
- z = rpz_find_zone(r, dname, dnamelen, rr_class,
+ z = rpz_find_zone(r->local_zones, dname, dnamelen, rr_class,
1 /* only exact */, 1 /* wr lock */, 1 /* keep lock*/);
if(!z) {
- verbose(VERB_ALGO, "RPZ: cannot remove RR from IXFR, "
+ verbose(VERB_ALGO, "rpz: cannot remove RR from IXFR, "
"RPZ domain not found");
return;
}
@@ -891,7 +1316,7 @@ rpz_remove_response_ip_trigger(struct rpz* r, uint8_t* dname, size_t dnamelen,
lock_rw_wrlock(&r->respip_set->lock);
if(!(node = (struct resp_addr*)addr_tree_find(
&r->respip_set->ip_tree, &addr, addrlen, net))) {
- verbose(VERB_ALGO, "RPZ: cannot remove RR from IXFR, "
+ verbose(VERB_ALGO, "rpz: cannot remove RR from IXFR, "
"RPZ domain not found");
lock_rw_unlock(&r->respip_set->lock);
return;
@@ -944,118 +1369,998 @@ rpz_remove_rr(struct rpz* r, size_t aznamelen, uint8_t* dname, size_t dnamelen,
/** print log information for an applied RPZ policy. Based on local-zone's
* lz_inform_print().
+ * The repinfo contains the reply address. If it is NULL, the module
+ * state is used to report the first IP address (if any).
+ * The dname is used, for the applied rpz, if NULL, addrnode is used.
*/
static void
-log_rpz_apply(uint8_t* dname, enum rpz_action a, struct query_info* qinfo,
- struct comm_reply* repinfo, char* log_name)
+log_rpz_apply(char* trigger, uint8_t* dname, struct addr_tree_node* addrnode,
+ enum rpz_action a, struct query_info* qinfo,
+ struct comm_reply* repinfo, struct module_qstate* ms, char* log_name)
{
- char ip[128], txt[512];
+ char ip[128], txt[512], portstr[32];
char dnamestr[LDNS_MAX_DOMAINLEN+1];
- uint16_t port = ntohs(((struct sockaddr_in*)&repinfo->addr)->sin_port);
- dname_str(dname, dnamestr);
- addr_to_str(&repinfo->addr, repinfo->addrlen, ip, sizeof(ip));
- if(log_name)
- snprintf(txt, sizeof(txt), "RPZ applied [%s] %s %s %s@%u",
- log_name, dnamestr, rpz_action_to_string(a), ip,
- (unsigned)port);
- else
- snprintf(txt, sizeof(txt), "RPZ applied %s %s %s@%u",
- dnamestr, rpz_action_to_string(a), ip, (unsigned)port);
+ uint16_t port = 0;
+ if(dname) {
+ dname_str(dname, dnamestr);
+ } else if(addrnode) {
+ char a[128];
+ addr_to_str(&addrnode->addr, addrnode->addrlen, a, sizeof(a));
+ snprintf(dnamestr, sizeof(dnamestr), "%s/%d", a, addrnode->net);
+ } else {
+ dnamestr[0]=0;
+ }
+ if(repinfo) {
+ addr_to_str(&repinfo->addr, repinfo->addrlen, ip, sizeof(ip));
+ port = ntohs(((struct sockaddr_in*)&repinfo->addr)->sin_port);
+ } else if(ms && ms->mesh_info && ms->mesh_info->reply_list) {
+ addr_to_str(&ms->mesh_info->reply_list->query_reply.addr, ms->mesh_info->reply_list->query_reply.addrlen, ip, sizeof(ip));
+ port = ntohs(((struct sockaddr_in*)&ms->mesh_info->reply_list->query_reply.addr)->sin_port);
+ } else {
+ ip[0]=0;
+ port = 0;
+ }
+ snprintf(portstr, sizeof(portstr), "@%u", (unsigned)port);
+ snprintf(txt, sizeof(txt), "rpz: applied %s%s%s%s%s%s %s %s%s",
+ (log_name?"[":""), (log_name?log_name:""), (log_name?"] ":""),
+ (strcmp(trigger,"qname")==0?"":trigger),
+ (strcmp(trigger,"qname")==0?"":" "),
+ dnamestr, rpz_action_to_string(a),
+ (ip[0]?ip:""), (ip[0]?portstr:""));
log_nametypeclass(0, txt, qinfo->qname, qinfo->qtype, qinfo->qclass);
}
-int
-rpz_apply_qname_trigger(struct auth_zones* az, struct module_env* env,
- struct query_info* qinfo, struct edns_data* edns, sldns_buffer* buf,
- struct regional* temp, struct comm_reply* repinfo,
- uint8_t* taglist, size_t taglen, struct ub_server_stats* stats)
+static struct clientip_synthesized_rr*
+rpz_ipbased_trigger_lookup(struct clientip_synthesized_rrset* set,
+ struct sockaddr_storage* addr, socklen_t addrlen, char* triggername)
{
+ struct clientip_synthesized_rr* raddr = NULL;
+ enum rpz_action action = RPZ_INVALID_ACTION;
+
+ lock_rw_rdlock(&set->lock);
+
+ raddr = (struct clientip_synthesized_rr*)addr_tree_lookup(&set->entries,
+ addr, addrlen);
+ if(raddr != NULL) {
+ lock_rw_rdlock(&raddr->lock);
+ action = raddr->action;
+ if(verbosity >= VERB_ALGO) {
+ char ip[256], net[256];
+ addr_to_str(addr, addrlen, ip, sizeof(ip));
+ addr_to_str(&raddr->node.addr, raddr->node.addrlen,
+ net, sizeof(net));
+ verbose(VERB_ALGO, "rpz: trigger %s %s/%d on %s action=%s",
+ triggername, net, raddr->node.net, ip, rpz_action_to_string(action));
+ }
+ }
+ lock_rw_unlock(&set->lock);
+
+ return raddr;
+}
+
+static inline
+struct clientip_synthesized_rr*
+rpz_resolve_client_action_and_zone(struct auth_zones* az, struct query_info* qinfo,
+ struct comm_reply* repinfo, uint8_t* taglist, size_t taglen,
+ struct ub_server_stats* stats,
+ /* output parameters */
+ struct local_zone** z_out, struct auth_zone** a_out, struct rpz** r_out)
+{
+ struct clientip_synthesized_rr* node = NULL;
+ struct auth_zone* a = NULL;
struct rpz* r = NULL;
- struct auth_zone* a;
- int ret;
- enum localzone_type lzt;
struct local_zone* z = NULL;
- struct local_data* ld = NULL;
+
lock_rw_rdlock(&az->rpz_lock);
+
for(a = az->rpz_first; a; a = a->rpz_az_next) {
lock_rw_rdlock(&a->lock);
r = a->rpz;
- if(!r->disabled && (!r->taglist || taglist_intersect(r->taglist,
- r->taglistlen, taglist, taglen))) {
- z = rpz_find_zone(r, qinfo->qname, qinfo->qname_len,
- qinfo->qclass, 0, 0, 0);
- if(z && r->action_override == RPZ_DISABLED_ACTION) {
- if(r->log)
- log_rpz_apply(z->name,
- r->action_override,
- qinfo, repinfo, r->log_name);
- /* TODO only register stats when stats_extended?
- * */
- stats->rpz_action[r->action_override]++;
+ if(r->disabled) {
+ lock_rw_unlock(&a->lock);
+ continue;
+ }
+ if(r->taglist && !taglist_intersect(r->taglist,
+ r->taglistlen, taglist, taglen)) {
+ lock_rw_unlock(&a->lock);
+ continue;
+ }
+ z = rpz_find_zone(r->local_zones, qinfo->qname, qinfo->qname_len,
+ qinfo->qclass, 0, 0, 0);
+ node = rpz_ipbased_trigger_lookup(r->client_set, &repinfo->addr, repinfo->addrlen, "clientip");
+ if((z || node) && r->action_override == RPZ_DISABLED_ACTION) {
+ if(r->log)
+ log_rpz_apply((node?"clientip":"qname"),
+ (z?z->name:NULL),
+ (node?&node->node:NULL),
+ r->action_override,
+ qinfo, repinfo, NULL, r->log_name);
+ stats->rpz_action[r->action_override]++;
+ if(z != NULL) {
lock_rw_unlock(&z->lock);
z = NULL;
}
- if(z)
- break;
+ if(node != NULL) {
+ lock_rw_unlock(&node->lock);
+ node = NULL;
+ }
}
- lock_rw_unlock(&a->lock); /* not found in this auth_zone */
+ if(z || node) {
+ break;
+ }
+ /* not found in this auth_zone */
+ lock_rw_unlock(&a->lock);
}
+
lock_rw_unlock(&az->rpz_lock);
- if(!z)
- return 0; /* not holding auth_zone.lock anymore */
- log_assert(r);
- if(r->action_override == RPZ_NO_OVERRIDE_ACTION)
- lzt = z->type;
- else
- lzt = rpz_action_to_localzone_type(r->action_override);
+ *r_out = r;
+ *a_out = a;
+ *z_out = z;
+
+ return node;
+}
+
+static inline int
+rpz_is_udp_query(struct comm_reply* repinfo) {
+ return repinfo != NULL
+ ? (repinfo->c != NULL
+ ? repinfo->c->type == comm_udp
+ : 0)
+ : 0;
+}
+
+/** encode answer consisting of 1 rrset */
+static int
+rpz_local_encode(struct module_env* env, struct query_info* qinfo,
+ struct edns_data* edns, struct comm_reply* repinfo, sldns_buffer* buf,
+ struct regional* temp, struct ub_packed_rrset_key* rrset, int ansec,
+ int rcode, struct ub_packed_rrset_key* soa_rrset)
+{
+ struct reply_info rep;
+ uint16_t udpsize;
+ struct ub_packed_rrset_key* rrsetlist[3];
+
+ memset(&rep, 0, sizeof(rep));
+ rep.flags = (uint16_t)((BIT_QR | BIT_AA | BIT_RA) | rcode);
+ rep.qdcount = 1;
+ rep.rrset_count = ansec;
+ rep.rrsets = rrsetlist;
+ if(ansec > 0) {
+ rep.an_numrrsets = 1;
+ rep.rrsets[0] = rrset;
+ rep.ttl = ((struct packed_rrset_data*)rrset->entry.data)->rr_ttl[0];
+ }
+ if(soa_rrset != NULL) {
+ rep.ar_numrrsets = 1;
+ rep.rrsets[rep.rrset_count] = soa_rrset;
+ rep.rrset_count ++;
+ if(rep.ttl < ((struct packed_rrset_data*)soa_rrset->entry.data)->rr_ttl[0]) {
+ rep.ttl = ((struct packed_rrset_data*)soa_rrset->entry.data)->rr_ttl[0];
+ }
+ }
+
+ udpsize = edns->udp_size;
+ edns->edns_version = EDNS_ADVERTISED_VERSION;
+ edns->udp_size = EDNS_ADVERTISED_SIZE;
+ edns->ext_rcode = 0;
+ edns->bits &= EDNS_DO;
+ if(!inplace_cb_reply_local_call(env, qinfo, NULL, &rep, rcode, edns,
+ repinfo, temp, env->now_tv) ||
+ !reply_info_answer_encode(qinfo, &rep,
+ *(uint16_t*)sldns_buffer_begin(buf), sldns_buffer_read_u16_at(buf, 2),
+ buf, 0, 0, temp, udpsize, edns, (int)(edns->bits&EDNS_DO), 0)) {
+ error_encode(buf, (LDNS_RCODE_SERVFAIL|BIT_AA), qinfo,
+ *(uint16_t*)sldns_buffer_begin(buf),
+ sldns_buffer_read_u16_at(buf, 2), edns);
+ }
+
+ return 1;
+}
+
+static struct local_rrset*
+rpz_find_synthesized_rrset(int qtype, struct clientip_synthesized_rr* data) {
+ struct local_rrset* cursor = data->data;
+ while( cursor != NULL) {
+ struct packed_rrset_key* packed_rrset = &cursor->rrset->rk;
+ if(htons(qtype) == packed_rrset->type) {
+ return cursor;
+ }
+ cursor = cursor->next;
+ }
+ return NULL;
+}
+
+/** allocate SOA record ubrrsetkey in region */
+static struct ub_packed_rrset_key*
+make_soa_ubrrset(struct auth_zone* auth_zone, struct auth_rrset* soa,
+ struct regional* temp)
+{
+ struct ub_packed_rrset_key csoa;
+ if(!soa)
+ return NULL;
+ memset(&csoa, 0, sizeof(csoa));
+ csoa.entry.key = &csoa;
+ csoa.rk.rrset_class = htons(LDNS_RR_CLASS_IN);
+ csoa.rk.type = htons(LDNS_RR_TYPE_SOA);
+ csoa.rk.flags |= PACKED_RRSET_FIXEDTTL
+ | PACKED_RRSET_RPZ;
+ csoa.rk.dname = auth_zone->name;
+ csoa.rk.dname_len = auth_zone->namelen;
+ csoa.entry.hash = rrset_key_hash(&csoa.rk);
+ csoa.entry.data = soa->data;
+ return respip_copy_rrset(&csoa, temp);
+}
+
+static void
+rpz_apply_clientip_localdata_action(struct clientip_synthesized_rr* raddr,
+ struct module_env* env, struct query_info* qinfo,
+ struct edns_data* edns, struct comm_reply* repinfo, sldns_buffer* buf,
+ struct regional* temp, struct auth_zone* auth_zone)
+{
+ struct local_rrset* rrset;
+ enum rpz_action action = RPZ_INVALID_ACTION;
+ struct ub_packed_rrset_key* rp = NULL;
+ struct ub_packed_rrset_key* rsoa = NULL;
+ int rcode = LDNS_RCODE_NOERROR|BIT_AA;
+ int rrset_count = 1;
+
+ /* prepare synthesized answer for client */
+ action = raddr->action;
+ if(action == RPZ_LOCAL_DATA_ACTION && raddr->data == NULL ) {
+ verbose(VERB_ALGO, "rpz: bug: local-data action but no local data");
+ return;
+ }
+
+ /* check query type / rr type */
+ rrset = rpz_find_synthesized_rrset(qinfo->qtype, raddr);
+ if(rrset == NULL) {
+ verbose(VERB_ALGO, "rpz: unable to find local-data for query");
+ rrset_count = 0;
+ goto nodata;
+ }
+
+ rp = respip_copy_rrset(rrset->rrset, temp);
+ if(!rp) {
+ verbose(VERB_ALGO, "rpz: local data action: out of memory");
+ return;
+ }
+
+ rp->rk.flags |= PACKED_RRSET_FIXEDTTL | PACKED_RRSET_RPZ;
+ rp->rk.dname = qinfo->qname;
+ rp->rk.dname_len = qinfo->qname_len;
+ rp->entry.hash = rrset_key_hash(&rp->rk);
+nodata:
+ if(auth_zone) {
+ struct auth_rrset* soa = NULL;
+ soa = auth_zone_get_soa_rrset(auth_zone);
+ if(soa) {
+ rsoa = make_soa_ubrrset(auth_zone, soa, temp);
+ if(!rsoa) {
+ verbose(VERB_ALGO, "rpz: local data action soa: out of memory");
+ return;
+ }
+ }
+ }
+
+ rpz_local_encode(env, qinfo, edns, repinfo, buf, temp, rp,
+ rrset_count, rcode, rsoa);
+}
+
+/** add additional section SOA record to the reply.
+ * Since this gets fed into the normal iterator answer creation, it
+ * gets minimal-responses applied to it, that can remove the additional SOA
+ * again. */
+static int
+rpz_add_soa(struct reply_info* rep, struct module_qstate* ms,
+ struct auth_zone* az)
+{
+ struct auth_rrset* soa = NULL;
+ struct ub_packed_rrset_key* rsoa = NULL;
+ struct ub_packed_rrset_key** prevrrsets;
+ if(!az) return 1;
+ soa = auth_zone_get_soa_rrset(az);
+ if(!soa) return 1;
+ if(!rep) return 0;
+ rsoa = make_soa_ubrrset(az, soa, ms->region);
+ if(!rsoa) return 0;
+ prevrrsets = rep->rrsets;
+ rep->rrsets = regional_alloc_zero(ms->region,
+ sizeof(*rep->rrsets)*(rep->rrset_count+1));
+ if(!rep->rrsets)
+ return 0;
+ if(prevrrsets && rep->rrset_count > 0)
+ memcpy(rep->rrsets, prevrrsets, rep->rrset_count*sizeof(*rep->rrsets));
+ rep->rrset_count++;
+ rep->ar_numrrsets++;
+ rep->rrsets[rep->rrset_count-1] = rsoa;
+ return 1;
+}
+
+static inline struct dns_msg*
+rpz_dns_msg_new(struct regional* region)
+{
+ struct dns_msg* msg =
+ (struct dns_msg*)regional_alloc(region,
+ sizeof(struct dns_msg));
+ if(msg == NULL) { return NULL; }
+ memset(msg, 0, sizeof(struct dns_msg));
+
+ return msg;
+}
+static inline struct dns_msg*
+rpz_synthesize_nodata(struct rpz* ATTR_UNUSED(r), struct module_qstate* ms,
+ struct query_info* qinfo, struct auth_zone* az)
+{
+ struct dns_msg* msg = rpz_dns_msg_new(ms->region);
+ if(msg == NULL) { return msg; }
+ msg->qinfo = *qinfo;
+ msg->rep = construct_reply_info_base(ms->region,
+ LDNS_RCODE_NOERROR | BIT_RD | BIT_QR | BIT_AA | BIT_RA,
+ 1, /* qd */
+ 0, /* ttl */
+ 0, /* prettl */
+ 0, /* expttl */
+ 0, /* an */
+ 0, /* ns */
+ 0, /* ar */
+ 0, /* total */
+ sec_status_insecure);
+ if(msg->rep)
+ msg->rep->authoritative = 1;
+ if(!rpz_add_soa(msg->rep, ms, az))
+ return NULL;
+ return msg;
+}
+
+static inline struct dns_msg*
+rpz_synthesize_nxdomain(struct rpz* ATTR_UNUSED(r), struct module_qstate* ms,
+ struct query_info* qinfo, struct auth_zone* az)
+{
+ struct dns_msg* msg = rpz_dns_msg_new(ms->region);
+ if(msg == NULL) { return msg; }
+ msg->qinfo = *qinfo;
+ msg->rep = construct_reply_info_base(ms->region,
+ LDNS_RCODE_NXDOMAIN | BIT_RD | BIT_QR | BIT_AA | BIT_RA,
+ 1, /* qd */
+ 0, /* ttl */
+ 0, /* prettl */
+ 0, /* expttl */
+ 0, /* an */
+ 0, /* ns */
+ 0, /* ar */
+ 0, /* total */
+ sec_status_insecure);
+ if(msg->rep)
+ msg->rep->authoritative = 1;
+ if(!rpz_add_soa(msg->rep, ms, az))
+ return NULL;
+ return msg;
+}
+
+static inline struct dns_msg*
+rpz_synthesize_localdata_from_rrset(struct rpz* ATTR_UNUSED(r), struct module_qstate* ms,
+ struct query_info* qi, struct local_rrset* rrset, struct auth_zone* az)
+{
+ struct dns_msg* msg = NULL;
+ struct reply_info* new_reply_info;
+ struct ub_packed_rrset_key* rp;
+
+
+ msg = rpz_dns_msg_new(ms->region);
+ if(msg == NULL) { return NULL; }
+
+ new_reply_info = construct_reply_info_base(ms->region,
+ LDNS_RCODE_NOERROR | BIT_RD | BIT_QR | BIT_AA | BIT_RA,
+ 1, /* qd */
+ 0, /* ttl */
+ 0, /* prettl */
+ 0, /* expttl */
+ 1, /* an */
+ 0, /* ns */
+ 0, /* ar */
+ 1, /* total */
+ sec_status_insecure);
+ if(new_reply_info == NULL) {
+ log_err("out of memory");
+ return NULL;
+ }
+ new_reply_info->authoritative = 1;
+ rp = respip_copy_rrset(rrset->rrset, ms->region);
+ if(rp == NULL) {
+ log_err("out of memory");
+ return NULL;
+ }
+ rp->rk.dname = qi->qname;
+ rp->rk.dname_len = qi->qname_len;
+ /* this rrset is from the rpz data, or synthesized.
+ * It is not actually from the network, so we flag it with this
+ * flags as a fake RRset. If later the cache is used to look up
+ * rrsets, then the fake ones are not returned (if you look without
+ * the flag). For like CNAME lookups from the iterator or A, AAAA
+ * lookups for nameserver targets, it would use the without flag
+ * actual data. So that the actual network data and fake data
+ * are kept track of separately. */
+ rp->rk.flags |= PACKED_RRSET_RPZ;
+ new_reply_info->rrsets[0] = rp;
+ msg->rep = new_reply_info;
+ if(!rpz_add_soa(msg->rep, ms, az))
+ return NULL;
+ return msg;
+}
+
+static inline struct dns_msg*
+rpz_synthesize_nsip_localdata(struct rpz* r, struct module_qstate* ms,
+ struct clientip_synthesized_rr* data, struct auth_zone* az)
+{
+ struct query_info* qi = &ms->qinfo;
+ struct local_rrset* rrset;
+
+ rrset = rpz_find_synthesized_rrset(qi->qtype, data);
+ if(rrset == NULL) {
+ verbose(VERB_ALGO, "rpz: nsip: no matching local data found");
+ return NULL;
+ }
+
+ return rpz_synthesize_localdata_from_rrset(r, ms, &ms->qinfo, rrset, az);
+}
+
+/* copy'n'paste from localzone.c */
+static struct local_rrset*
+local_data_find_type(struct local_data* data, uint16_t type, int alias_ok)
+{
+ struct local_rrset* p;
+ type = htons(type);
+ for(p = data->rrsets; p; p = p->next) {
+ if(p->rrset->rk.type == type)
+ return p;
+ if(alias_ok && p->rrset->rk.type == htons(LDNS_RR_TYPE_CNAME))
+ return p;
+ }
+ return NULL;
+}
+
+/* based on localzone.c:local_data_answer() */
+static inline struct dns_msg*
+rpz_synthesize_nsdname_localdata(struct rpz* r, struct module_qstate* ms,
+ struct local_zone* z, struct matched_delegation_point const* match,
+ struct auth_zone* az)
+{
+ struct local_data key;
+ struct local_data* ld;
+ struct local_rrset* rrset;
+
+ if(match->dname == NULL) { return NULL; }
+
+ key.node.key = &key;
+ key.name = match->dname;
+ key.namelen = match->dname_len;
+ key.namelabs = dname_count_labels(match->dname);
+
+ rpz_log_dname("nsdname local data", key.name, key.namelen);
+
+ ld = (struct local_data*)rbtree_search(&z->data, &key.node);
+ if(ld == NULL) {
+ verbose(VERB_ALGO, "rpz: nsdname: impossible: qname not found");
+ return NULL;
+ }
+
+ rrset = local_data_find_type(ld, ms->qinfo.qtype, 1);
+ if(rrset == NULL) {
+ verbose(VERB_ALGO, "rpz: nsdname: no matching local data found");
+ return NULL;
+ }
+
+ return rpz_synthesize_localdata_from_rrset(r, ms, &ms->qinfo, rrset, az);
+}
+
+/* like local_data_answer for qname triggers after a cname */
+static struct dns_msg*
+rpz_synthesize_qname_localdata_msg(struct rpz* r, struct module_qstate* ms,
+ struct query_info* qinfo, struct local_zone* z, struct auth_zone* az)
+{
+ struct local_data key;
+ struct local_data* ld;
+ struct local_rrset* rrset;
+ key.node.key = &key;
+ key.name = qinfo->qname;
+ key.namelen = qinfo->qname_len;
+ key.namelabs = dname_count_labels(qinfo->qname);
+ ld = (struct local_data*)rbtree_search(&z->data, &key.node);
+ if(ld == NULL) {
+ verbose(VERB_ALGO, "rpz: qname after cname: name not found");
+ return NULL;
+ }
+ rrset = local_data_find_type(ld, qinfo->qtype, 1);
+ if(rrset == NULL) {
+ verbose(VERB_ALGO, "rpz: qname after cname: type not found");
+ return NULL;
+ }
+ return rpz_synthesize_localdata_from_rrset(r, ms, qinfo, rrset, az);
+}
+
+static int
+rpz_synthesize_qname_localdata(struct module_env* env, struct rpz* r,
+ struct local_zone* z, enum localzone_type lzt, struct query_info* qinfo,
+ struct edns_data* edns, sldns_buffer* buf, struct regional* temp,
+ struct comm_reply* repinfo, struct ub_server_stats* stats)
+{
+ struct local_data* ld = NULL;
+ int ret = 0;
if(r->action_override == RPZ_CNAME_OVERRIDE_ACTION) {
- qinfo->local_alias =
- regional_alloc_zero(temp, sizeof(struct local_rrset));
- if(!qinfo->local_alias) {
- lock_rw_unlock(&z->lock);
- lock_rw_unlock(&a->lock);
+ qinfo->local_alias = regional_alloc_zero(temp, sizeof(struct local_rrset));
+ if(qinfo->local_alias == NULL) {
return 0; /* out of memory */
}
- qinfo->local_alias->rrset =
- regional_alloc_init(temp, r->cname_override,
- sizeof(*r->cname_override));
- if(!qinfo->local_alias->rrset) {
- lock_rw_unlock(&z->lock);
- lock_rw_unlock(&a->lock);
+ qinfo->local_alias->rrset = regional_alloc_init(temp, r->cname_override,
+ sizeof(*r->cname_override));
+ if(qinfo->local_alias->rrset == NULL) {
return 0; /* out of memory */
}
qinfo->local_alias->rrset->rk.dname = qinfo->qname;
qinfo->local_alias->rrset->rk.dname_len = qinfo->qname_len;
- if(r->log)
- log_rpz_apply(z->name, RPZ_CNAME_OVERRIDE_ACTION,
- qinfo, repinfo, r->log_name);
+ if(r->log) {
+ log_rpz_apply("qname", z->name, NULL, RPZ_CNAME_OVERRIDE_ACTION,
+ qinfo, repinfo, NULL, r->log_name);
+ }
stats->rpz_action[RPZ_CNAME_OVERRIDE_ACTION]++;
- lock_rw_unlock(&z->lock);
- lock_rw_unlock(&a->lock);
return 0;
}
if(lzt == local_zone_redirect && local_data_answer(z, env, qinfo,
edns, repinfo, buf, temp, dname_count_labels(qinfo->qname),
&ld, lzt, -1, NULL, 0, NULL, 0)) {
- if(r->log)
- log_rpz_apply(z->name,
+ if(r->log) {
+ log_rpz_apply("qname", z->name, NULL,
localzone_type_to_rpz_action(lzt), qinfo,
- repinfo, r->log_name);
+ repinfo, NULL, r->log_name);
+ }
stats->rpz_action[localzone_type_to_rpz_action(lzt)]++;
- lock_rw_unlock(&z->lock);
- lock_rw_unlock(&a->lock);
return !qinfo->local_alias;
}
ret = local_zones_zone_answer(z, env, qinfo, edns, repinfo, buf, temp,
0 /* no local data used */, lzt);
- if(r->log)
- log_rpz_apply(z->name, localzone_type_to_rpz_action(lzt),
- qinfo, repinfo, r->log_name);
+ if(r->log) {
+ log_rpz_apply("qname", z->name, NULL, localzone_type_to_rpz_action(lzt),
+ qinfo, repinfo, NULL, r->log_name);
+ }
stats->rpz_action[localzone_type_to_rpz_action(lzt)]++;
+ return ret;
+}
+
+struct clientip_synthesized_rr*
+rpz_delegation_point_ipbased_trigger_lookup(struct rpz* rpz, struct iter_qstate* is)
+{
+ struct delegpt_addr* cursor;
+ struct clientip_synthesized_rr* action = NULL;
+ if(is->dp == NULL) { return NULL; }
+ for(cursor = is->dp->target_list;
+ cursor != NULL;
+ cursor = cursor->next_target) {
+ if(cursor->bogus) { continue; }
+ action = rpz_ipbased_trigger_lookup(rpz->ns_set, &cursor->addr,
+ cursor->addrlen, "nsip");
+ if(action != NULL) { return action; }
+ }
+ return NULL;
+}
+
+struct dns_msg*
+rpz_apply_nsip_trigger(struct module_qstate* ms, struct rpz* r,
+ struct clientip_synthesized_rr* raddr, struct auth_zone* az)
+{
+ enum rpz_action action = raddr->action;
+ struct dns_msg* ret = NULL;
+
+ if(r->action_override != RPZ_NO_OVERRIDE_ACTION) {
+ verbose(VERB_ALGO, "rpz: using override action=%s (replaces=%s)",
+ rpz_action_to_string(r->action_override), rpz_action_to_string(action));
+ action = r->action_override;
+ }
+
+ if(action == RPZ_LOCAL_DATA_ACTION && raddr->data == NULL) {
+ verbose(VERB_ALGO, "rpz: bug: nsip local data action but no local data");
+ ret = rpz_synthesize_nodata(r, ms, &ms->qinfo, az);
+ goto done;
+ }
+
+ switch(action) {
+ case RPZ_NXDOMAIN_ACTION:
+ ret = rpz_synthesize_nxdomain(r, ms, &ms->qinfo, az);
+ break;
+ case RPZ_NODATA_ACTION:
+ ret = rpz_synthesize_nodata(r, ms, &ms->qinfo, az);
+ break;
+ case RPZ_TCP_ONLY_ACTION:
+ /* basically a passthru here but the tcp-only will be
+ * honored before the query gets sent. */
+ ms->respip_action_info->action = respip_truncate;
+ ret = NULL;
+ break;
+ case RPZ_DROP_ACTION:
+ ret = rpz_synthesize_nodata(r, ms, &ms->qinfo, az);
+ ms->is_drop = 1;
+ break;
+ case RPZ_LOCAL_DATA_ACTION:
+ ret = rpz_synthesize_nsip_localdata(r, ms, raddr, az);
+ if(ret == NULL) { ret = rpz_synthesize_nodata(r, ms, &ms->qinfo, az); }
+ break;
+ case RPZ_PASSTHRU_ACTION:
+ ret = NULL;
+ break;
+ default:
+ verbose(VERB_ALGO, "rpz: nsip: bug: unhandled or invalid action: '%s'",
+ rpz_action_to_string(action));
+ ret = NULL;
+ }
+
+done:
+ if(r->log)
+ log_rpz_apply("nsip", NULL, &raddr->node,
+ action, &ms->qinfo, NULL, ms, r->log_name);
+ if(ms->env->worker)
+ ms->env->worker->stats.rpz_action[action]++;
+ lock_rw_unlock(&raddr->lock);
+ return ret;
+}
+
+struct dns_msg*
+rpz_apply_nsdname_trigger(struct module_qstate* ms, struct rpz* r,
+ struct local_zone* z, struct matched_delegation_point const* match,
+ struct auth_zone* az)
+{
+ struct dns_msg* ret = NULL;
+ enum rpz_action action = localzone_type_to_rpz_action(z->type);
+
+ if(r->action_override != RPZ_NO_OVERRIDE_ACTION) {
+ verbose(VERB_ALGO, "rpz: using override action=%s (replaces=%s)",
+ rpz_action_to_string(r->action_override), rpz_action_to_string(action));
+ action = r->action_override;
+ }
+
+ switch(action) {
+ case RPZ_NXDOMAIN_ACTION:
+ ret = rpz_synthesize_nxdomain(r, ms, &ms->qinfo, az);
+ break;
+ case RPZ_NODATA_ACTION:
+ ret = rpz_synthesize_nodata(r, ms, &ms->qinfo, az);
+ break;
+ case RPZ_TCP_ONLY_ACTION:
+ /* basically a passthru here but the tcp-only will be
+ * honored before the query gets sent. */
+ ms->respip_action_info->action = respip_truncate;
+ ret = NULL;
+ break;
+ case RPZ_DROP_ACTION:
+ ret = rpz_synthesize_nodata(r, ms, &ms->qinfo, az);
+ ms->is_drop = 1;
+ break;
+ case RPZ_LOCAL_DATA_ACTION:
+ ret = rpz_synthesize_nsdname_localdata(r, ms, z, match, az);
+ if(ret == NULL) { ret = rpz_synthesize_nodata(r, ms, &ms->qinfo, az); }
+ break;
+ case RPZ_PASSTHRU_ACTION:
+ ret = NULL;
+ break;
+ default:
+ verbose(VERB_ALGO, "rpz: nsip: bug: unhandled or invalid action: '%s'",
+ rpz_action_to_string(action));
+ ret = NULL;
+ }
+
+ if(r->log)
+ log_rpz_apply("nsdname", match->dname, NULL,
+ action, &ms->qinfo, NULL, ms, r->log_name);
+ if(ms->env->worker)
+ ms->env->worker->stats.rpz_action[action]++;
+ lock_rw_unlock(&z->lock);
+ return ret;
+}
+
+static struct local_zone*
+rpz_delegation_point_zone_lookup(struct delegpt* dp, struct local_zones* zones,
+ uint16_t qclass,
+ /* output parameter */
+ struct matched_delegation_point* match)
+{
+ struct delegpt_ns* nameserver;
+ struct local_zone* z = NULL;
+
+ /* the rpz specs match the nameserver names (NS records), not the
+ * name of the delegation point itself, to the nsdname triggers */
+ for(nameserver = dp->nslist;
+ nameserver != NULL;
+ nameserver = nameserver->next) {
+ z = rpz_find_zone(zones, nameserver->name, nameserver->namelen,
+ qclass, 0, 0, 0);
+ if(z != NULL) {
+ match->dname = nameserver->name;
+ match->dname_len = nameserver->namelen;
+ if(verbosity >= VERB_ALGO) {
+ char nm[255+1], zn[255+1];
+ dname_str(match->dname, nm);
+ dname_str(z->name, zn);
+ if(strcmp(nm, zn) != 0)
+ verbose(VERB_ALGO, "rpz: trigger nsdname %s on %s action=%s",
+ zn, nm, rpz_action_to_string(localzone_type_to_rpz_action(z->type)));
+ else
+ verbose(VERB_ALGO, "rpz: trigger nsdname %s action=%s",
+ nm, rpz_action_to_string(localzone_type_to_rpz_action(z->type)));
+ }
+ break;
+ }
+ }
+
+ return z;
+}
+
+struct dns_msg*
+rpz_callback_from_iterator_module(struct module_qstate* ms, struct iter_qstate* is)
+{
+ struct auth_zones* az;
+ struct auth_zone* a;
+ struct clientip_synthesized_rr* raddr = NULL;
+ struct rpz* r = NULL;
+ struct local_zone* z = NULL;
+ struct matched_delegation_point match = {0};
+
+ if(ms->env == NULL || ms->env->auth_zones == NULL) { return 0; }
+
+ az = ms->env->auth_zones;
+
+ verbose(VERB_ALGO, "rpz: iterator module callback: have_rpz=%d", az->rpz_first != NULL);
+
+ lock_rw_rdlock(&az->rpz_lock);
+
+ /* precedence of RPZ works, loosely, like this:
+ * CNAMEs in order of the CNAME chain. rpzs in the order they are
+ * configured. In an RPZ: first client-IP addr, then QNAME, then
+ * response IP, then NSDNAME, then NSIP. Longest match first. Smallest
+ * one from a set. */
+ /* we use the precedence rules for the topics and triggers that
+ * are pertinent at this stage of the resolve processing */
+ for(a = az->rpz_first; a != NULL; a = a->rpz_az_next) {
+ lock_rw_rdlock(&a->lock);
+ r = a->rpz;
+ if(r->disabled) {
+ lock_rw_unlock(&a->lock);
+ continue;
+ }
+
+ /* the nsdname has precedence over the nsip triggers */
+ z = rpz_delegation_point_zone_lookup(is->dp, r->nsdname_zones,
+ ms->qinfo.qclass, &match);
+ if(z != NULL) {
+ lock_rw_unlock(&a->lock);
+ break;
+ }
+
+ raddr = rpz_delegation_point_ipbased_trigger_lookup(r, is);
+ if(raddr != NULL) {
+ lock_rw_unlock(&a->lock);
+ break;
+ }
+ lock_rw_unlock(&a->lock);
+ }
+
+ lock_rw_unlock(&az->rpz_lock);
+
+ if(raddr == NULL && z == NULL) { return NULL; }
+ else if(raddr != NULL) {
+ if(z) {
+ lock_rw_unlock(&z->lock);
+ }
+ return rpz_apply_nsip_trigger(ms, r, raddr, a);
+ } else if(z != NULL) {
+ if(raddr) {
+ lock_rw_unlock(&raddr->lock);
+ }
+ return rpz_apply_nsdname_trigger(ms, r, z, &match, a);
+ } else { return NULL; }
+}
+
+struct dns_msg* rpz_callback_from_iterator_cname(struct module_qstate* ms,
+ struct iter_qstate* is)
+{
+ struct auth_zones* az;
+ struct auth_zone* a = NULL;
+ struct rpz* r = NULL;
+ struct local_zone* z = NULL;
+ enum localzone_type lzt;
+ struct dns_msg* ret = NULL;
+
+ if(ms->env == NULL || ms->env->auth_zones == NULL) { return 0; }
+ az = ms->env->auth_zones;
+
+ lock_rw_rdlock(&az->rpz_lock);
+
+ for(a = az->rpz_first; a; a = a->rpz_az_next) {
+ lock_rw_rdlock(&a->lock);
+ r = a->rpz;
+ if(r->disabled) {
+ lock_rw_unlock(&a->lock);
+ continue;
+ }
+ z = rpz_find_zone(r->local_zones, is->qchase.qname,
+ is->qchase.qname_len, is->qchase.qclass, 0, 0, 0);
+ if(z && r->action_override == RPZ_DISABLED_ACTION) {
+ if(r->log)
+ log_rpz_apply("qname", z->name, NULL,
+ r->action_override,
+ &ms->qinfo, NULL, ms, r->log_name);
+ if(ms->env->worker)
+ ms->env->worker->stats.rpz_action[r->action_override]++;
+ lock_rw_unlock(&z->lock);
+ z = NULL;
+ }
+ if(z) {
+ break;
+ }
+ /* not found in this auth_zone */
+ lock_rw_unlock(&a->lock);
+ }
+ lock_rw_unlock(&az->rpz_lock);
+
+ if(z == NULL)
+ return NULL;
+ if(r->action_override == RPZ_NO_OVERRIDE_ACTION) {
+ lzt = z->type;
+ } else {
+ lzt = rpz_action_to_localzone_type(r->action_override);
+ }
+
+ if(verbosity >= VERB_ALGO) {
+ char nm[255+1], zn[255+1];
+ dname_str(is->qchase.qname, nm);
+ dname_str(z->name, zn);
+ if(strcmp(zn, nm) != 0)
+ verbose(VERB_ALGO, "rpz: qname trigger after cname %s on %s, with action=%s",
+ zn, nm, rpz_action_to_string(localzone_type_to_rpz_action(lzt)));
+ else
+ verbose(VERB_ALGO, "rpz: qname trigger after cname %s, with action=%s",
+ nm, rpz_action_to_string(localzone_type_to_rpz_action(lzt)));
+ }
+ switch(localzone_type_to_rpz_action(lzt)) {
+ case RPZ_NXDOMAIN_ACTION:
+ ret = rpz_synthesize_nxdomain(r, ms, &is->qchase, a);
+ break;
+ case RPZ_NODATA_ACTION:
+ ret = rpz_synthesize_nodata(r, ms, &is->qchase, a);
+ break;
+ case RPZ_TCP_ONLY_ACTION:
+ /* basically a passthru here but the tcp-only will be
+ * honored before the query gets sent. */
+ ms->respip_action_info->action = respip_truncate;
+ ret = NULL;
+ break;
+ case RPZ_DROP_ACTION:
+ ret = rpz_synthesize_nodata(r, ms, &is->qchase, a);
+ ms->is_drop = 1;
+ break;
+ case RPZ_LOCAL_DATA_ACTION:
+ ret = rpz_synthesize_qname_localdata_msg(r, ms, &is->qchase, z, a);
+ if(ret == NULL) { ret = rpz_synthesize_nodata(r, ms, &is->qchase, a); }
+ break;
+ case RPZ_PASSTHRU_ACTION:
+ ret = NULL;
+ break;
+ default:
+ verbose(VERB_ALGO, "rpz: qname trigger after cname: bug: unhandled or invalid action: '%s'",
+ rpz_action_to_string(localzone_type_to_rpz_action(lzt)));
+ ret = NULL;
+ }
+ lock_rw_unlock(&z->lock);
+ lock_rw_unlock(&a->lock);
+ return ret;
+}
+
+static int
+rpz_apply_maybe_clientip_trigger(struct auth_zones* az, struct module_env* env,
+ struct query_info* qinfo, struct edns_data* edns, struct comm_reply* repinfo,
+ uint8_t* taglist, size_t taglen, struct ub_server_stats* stats,
+ sldns_buffer* buf, struct regional* temp,
+ /* output parameters */
+ struct local_zone** z_out, struct auth_zone** a_out, struct rpz** r_out)
+{
+ int ret = 0;
+ enum rpz_action client_action;
+ struct clientip_synthesized_rr* node = rpz_resolve_client_action_and_zone(
+ az, qinfo, repinfo, taglist, taglen, stats, z_out, a_out, r_out);
+
+ client_action = ((node == NULL) ? RPZ_INVALID_ACTION : node->action);
+
+ if(*z_out == NULL || (client_action != RPZ_INVALID_ACTION &&
+ client_action != RPZ_PASSTHRU_ACTION)) {
+ if(client_action == RPZ_PASSTHRU_ACTION
+ || client_action == RPZ_INVALID_ACTION
+ || (client_action == RPZ_TCP_ONLY_ACTION
+ && !rpz_is_udp_query(repinfo))) {
+ ret = 0;
+ goto done;
+ }
+ stats->rpz_action[client_action]++;
+ if(client_action == RPZ_LOCAL_DATA_ACTION) {
+ rpz_apply_clientip_localdata_action(node, env, qinfo,
+ edns, repinfo, buf, temp, *a_out);
+ } else {
+ if(*r_out && (*r_out)->log)
+ log_rpz_apply(
+ (node?"clientip":"qname"),
+ ((*z_out)?(*z_out)->name:NULL),
+ (node?&node->node:NULL),
+ client_action, qinfo, repinfo, NULL,
+ (*r_out)->log_name);
+ local_zones_zone_answer(*z_out /*likely NULL, no zone*/, env, qinfo, edns,
+ repinfo, buf, temp, 0 /* no local data used */,
+ rpz_action_to_localzone_type(client_action));
+ }
+ ret = 1;
+ goto done;
+ }
+ ret = -1;
+done:
+ if(node != NULL) {
+ lock_rw_unlock(&node->lock);
+ }
+ return ret;
+}
+
+int
+rpz_callback_from_worker_request(struct auth_zones* az, struct module_env* env,
+ struct query_info* qinfo, struct edns_data* edns, sldns_buffer* buf,
+ struct regional* temp, struct comm_reply* repinfo, uint8_t* taglist,
+ size_t taglen, struct ub_server_stats* stats)
+{
+ struct rpz* r = NULL;
+ struct auth_zone* a = NULL;
+ struct local_zone* z = NULL;
+ int ret;
+ enum localzone_type lzt;
+
+ int clientip_trigger = rpz_apply_maybe_clientip_trigger(az, env, qinfo,
+ edns, repinfo, taglist, taglen, stats, buf, temp, &z, &a, &r);
+ if(clientip_trigger >= 0) {
+ if(a) {
+ lock_rw_unlock(&a->lock);
+ }
+ if(z) {
+ lock_rw_unlock(&z->lock);
+ }
+ return clientip_trigger;
+ }
+
+ if(z == NULL) {
+ if(a) {
+ lock_rw_unlock(&a->lock);
+ }
+ return 0;
+ }
+
+ log_assert(r);
+
+ if(r->action_override == RPZ_NO_OVERRIDE_ACTION) {
+ lzt = z->type;
+ } else {
+ lzt = rpz_action_to_localzone_type(r->action_override);
+ }
+
+ if(verbosity >= VERB_ALGO) {
+ char nm[255+1], zn[255+1];
+ dname_str(qinfo->qname, nm);
+ dname_str(z->name, zn);
+ if(strcmp(zn, nm) != 0)
+ verbose(VERB_ALGO, "rpz: qname trigger %s on %s with action=%s",
+ zn, nm, rpz_action_to_string(localzone_type_to_rpz_action(lzt)));
+ else
+ verbose(VERB_ALGO, "rpz: qname trigger %s with action=%s",
+ nm, rpz_action_to_string(localzone_type_to_rpz_action(lzt)));
+ }
+
+ ret = rpz_synthesize_qname_localdata(env, r, z, lzt, qinfo, edns, buf, temp,
+ repinfo, stats);
+
lock_rw_unlock(&z->lock);
lock_rw_unlock(&a->lock);
diff --git a/contrib/unbound/services/rpz.h b/contrib/unbound/services/rpz.h
index d5996a6cfa26..691475743606 100644
--- a/contrib/unbound/services/rpz.h
+++ b/contrib/unbound/services/rpz.h
@@ -50,6 +50,7 @@
#include "sldns/sbuffer.h"
#include "daemon/stats.h"
#include "respip/respip.h"
+struct iter_qstate;
/**
* RPZ triggers, only the QNAME trigger is currently supported in Unbound.
@@ -83,6 +84,27 @@ enum rpz_action {
RPZ_CNAME_OVERRIDE_ACTION, /* RPZ CNAME action override*/
};
+struct clientip_synthesized_rrset{
+ struct regional* region;
+ struct rbtree_type entries;
+ lock_rw_type lock; /* lock on the respip tree */
+};
+
+struct clientip_synthesized_rr {
+ /** node in address tree */
+ struct addr_tree_node node;
+ /** lock on the node item */
+ lock_rw_type lock;
+ /** tag bitlist */
+ uint8_t* taglist;
+ /** length of the taglist (in bytes) */
+ size_t taglen;
+ /** action for this address span */
+ enum rpz_action action;
+ /** "local data" for this node */
+ struct local_rrset* data;
+};
+
/**
* RPZ containing policies. Pointed to from corresponding auth-zone. Part of a
* linked list to keep configuration order. Iterating or changing the linked
@@ -92,6 +114,9 @@ enum rpz_action {
struct rpz {
struct local_zones* local_zones;
struct respip_set* respip_set;
+ struct clientip_synthesized_rrset* client_set;
+ struct clientip_synthesized_rrset* ns_set;
+ struct local_zones* nsdname_zones;
uint8_t* taglist;
size_t taglistlen;
enum rpz_action action_override;
@@ -147,16 +172,39 @@ void rpz_remove_rr(struct rpz* r, size_t aznamelen, uint8_t* dname,
* @param temp: scratchpad
* @param repinfo: reply info
* @param taglist: taglist to lookup.
- * @param taglen: lenth of taglist.
+ * @param taglen: length of taglist.
* @param stats: worker stats struct
* @return: 1 if client answer is ready, 0 to continue resolving
*/
-int rpz_apply_qname_trigger(struct auth_zones* az, struct module_env* env,
+int rpz_callback_from_worker_request(struct auth_zones* az, struct module_env* env,
struct query_info* qinfo, struct edns_data* edns, sldns_buffer* buf,
struct regional* temp, struct comm_reply* repinfo,
uint8_t* taglist, size_t taglen, struct ub_server_stats* stats);
/**
+ * Callback to process when the iterator module is about to send queries.
+ * Checks for nsip and nsdname triggers.
+ * @param qstate: the query state.
+ * @param iq: iterator module query state.
+ * @return NULL if nothing is done. Or a new message with the contents from
+ * the rpz, based on the delegation point. It is allocated in the
+ * qstate region.
+ */
+struct dns_msg* rpz_callback_from_iterator_module(struct module_qstate* qstate,
+ struct iter_qstate* iq);
+
+/**
+ * Callback to process when the iterator module has followed a cname.
+ * There can be a qname trigger for the new query name.
+ * @param qstate: the query state.
+ * @param iq: iterator module query state.
+ * @return NULL if nothing is done. Or a new message with the contents from
+ * the rpz, based on the iq.qchase. It is allocated in the qstate region.
+ */
+struct dns_msg* rpz_callback_from_iterator_cname(struct module_qstate* qstate,
+ struct iter_qstate* iq);
+
+/**
* Delete RPZ
* @param r: RPZ struct to delete
*/
@@ -186,7 +234,7 @@ enum rpz_action
respip_action_to_rpz_action(enum respip_action a);
/**
- * Prepare RPZ after procesing feed content.
+ * Prepare RPZ after processing feed content.
* @param r: RPZ to use
*/
void rpz_finish_config(struct rpz* r);
diff --git a/contrib/unbound/sldns/parseutil.h b/contrib/unbound/sldns/parseutil.h
index 74d7c727571a..208fd2fbca8b 100644
--- a/contrib/unbound/sldns/parseutil.h
+++ b/contrib/unbound/sldns/parseutil.h
@@ -58,7 +58,7 @@ time_t sldns_mktime_from_utc(const struct tm *tm);
* The function interprets time as the number of seconds since epoch
* with respect to now using serial arithmetics (rfc1982).
* That number of seconds is then converted to broken-out time information.
- * This is especially usefull when converting the inception and expiration
+ * This is especially useful when converting the inception and expiration
* fields of RRSIG records.
*
* \param[in] time number of seconds since epoch (midnight, January 1st, 1970)
diff --git a/contrib/unbound/sldns/str2wire.c b/contrib/unbound/sldns/str2wire.c
index fbd615cbfd7d..ddaccd1b292d 100644
--- a/contrib/unbound/sldns/str2wire.c
+++ b/contrib/unbound/sldns/str2wire.c
@@ -1427,7 +1427,7 @@ sldns_str2wire_svcbparam_parse_next_unescaped_comma(const char *val)
}
/* The source is already properly unescaped, this double unescaping is purely to allow for
- * comma's in comma seperated alpn lists.
+ * comma's in comma separated alpn lists.
*
* In draft-ietf-dnsop-svcb-https-06 Section 7:
* To enable simpler parsing, this SvcParamValue MUST NOT contain escape sequences.
@@ -1565,7 +1565,7 @@ sldns_str2wire_svcparam_value(const char *key, size_t key_len,
return LDNS_WIREPARSE_ERR_GENERAL;
}
-int sldns_str2wire_svcparam_buf(const char* str, uint8_t* rd, size_t* rd_len)
+static int sldns_str2wire_svcparam_buf(const char* str, uint8_t* rd, size_t* rd_len)
{
const char* eq_pos;
char unescaped_val[LDNS_MAX_RDFLEN];
diff --git a/contrib/unbound/sldns/wire2str.h b/contrib/unbound/sldns/wire2str.h
index b1ad459e3780..548c66300d92 100644
--- a/contrib/unbound/sldns/wire2str.h
+++ b/contrib/unbound/sldns/wire2str.h
@@ -59,7 +59,7 @@ char* sldns_wire2str_pkt(uint8_t* data, size_t len);
char* sldns_wire2str_rr(uint8_t* rr, size_t len);
/**
- * Conver wire dname to a string.
+ * Convert wire dname to a string.
* @param dname: the dname in uncompressed wireformat.
* @param dname_len: length of the dname.
* @return string or NULL on failure.
diff --git a/contrib/unbound/smallapp/unbound-anchor.c b/contrib/unbound/smallapp/unbound-anchor.c
index 2ddd7ff69033..027980be117a 100644
--- a/contrib/unbound/smallapp/unbound-anchor.c
+++ b/contrib/unbound/smallapp/unbound-anchor.c
@@ -2037,13 +2037,13 @@ write_builtin_anchor(const char* file)
const char* builtin_root_anchor = get_builtin_ds();
FILE* out = fopen(file, "w");
if(!out) {
- if(verb) printf("%s: %s\n", file, strerror(errno));
- if(verb) printf(" could not write builtin anchor\n");
+ printf("could not write builtin anchor, to file %s: %s\n",
+ file, strerror(errno));
return;
}
if(!fwrite(builtin_root_anchor, strlen(builtin_root_anchor), 1, out)) {
- if(verb) printf("%s: %s\n", file, strerror(errno));
- if(verb) printf(" could not complete write builtin anchor\n");
+ printf("could not complete write builtin anchor, to file %s: %s\n",
+ file, strerror(errno));
}
fclose(out);
}
diff --git a/contrib/unbound/smallapp/unbound-checkconf.c b/contrib/unbound/smallapp/unbound-checkconf.c
index 8e5656355843..8f114b862c9a 100644
--- a/contrib/unbound/smallapp/unbound-checkconf.c
+++ b/contrib/unbound/smallapp/unbound-checkconf.c
@@ -54,6 +54,7 @@
#include "iterator/iter_hints.h"
#include "validator/validator.h"
#include "services/localzone.h"
+#include "services/listen_dnsport.h"
#include "services/view.h"
#include "services/authzone.h"
#include "respip/respip.h"
@@ -334,19 +335,64 @@ interfacechecks(struct config_file* cfg)
int d;
struct sockaddr_storage a;
socklen_t alen;
- int i, j;
+ int i, j, i2, j2;
+ char*** resif = NULL;
+ int* num_resif = NULL;
+
+ if(cfg->num_ifs != 0) {
+ resif = (char***)calloc(cfg->num_ifs, sizeof(char**));
+ if(!resif) fatal_exit("malloc failure");
+ num_resif = (int*)calloc(cfg->num_ifs, sizeof(int));
+ if(!num_resif) fatal_exit("malloc failure");
+ }
for(i=0; i<cfg->num_ifs; i++) {
- if(!extstrtoaddr(cfg->ifs[i], &a, &alen)) {
- fatal_exit("cannot parse interface specified as '%s'",
- cfg->ifs[i]);
- }
- for(j=0; j<cfg->num_ifs; j++) {
- if(i!=j && strcmp(cfg->ifs[i], cfg->ifs[j])==0)
+ /* search for duplicates in IP or ifname arguments */
+ for(i2=0; i2<i; i2++) {
+ if(strcmp(cfg->ifs[i], cfg->ifs[i2]) == 0) {
fatal_exit("interface: %s present twice, "
"cannot bind same ports twice.",
cfg->ifs[i]);
+ }
}
+ if(!resolve_interface_names(&cfg->ifs[i], 1, NULL, &resif[i],
+ &num_resif[i])) {
+ fatal_exit("could not resolve interface names, for %s",
+ cfg->ifs[i]);
+ }
+ /* search for duplicates in the returned addresses */
+ for(j=0; j<num_resif[i]; j++) {
+ if(!extstrtoaddr(resif[i][j], &a, &alen)) {
+ if(strcmp(cfg->ifs[i], resif[i][j]) != 0)
+ fatal_exit("cannot parse interface address '%s' from the interface specified as '%s'",
+ resif[i][j], cfg->ifs[i]);
+ else
+ fatal_exit("cannot parse interface specified as '%s'",
+ cfg->ifs[i]);
+ }
+ for(i2=0; i2<i; i2++) {
+ for(j2=0; j2<num_resif[i2]; j2++) {
+ if(strcmp(resif[i][j], resif[i2][j2])
+ == 0) {
+ char info1[1024], info2[1024];
+ if(strcmp(cfg->ifs[i], resif[i][j]) != 0)
+ snprintf(info1, sizeof(info1), "address %s from interface: %s", resif[i][j], cfg->ifs[i]);
+ else snprintf(info1, sizeof(info1), "interface: %s", cfg->ifs[i]);
+ if(strcmp(cfg->ifs[i2], resif[i2][j2]) != 0)
+ snprintf(info2, sizeof(info2), "address %s from interface: %s", resif[i2][j2], cfg->ifs[i2]);
+ else snprintf(info2, sizeof(info2), "interface: %s", cfg->ifs[i2]);
+ fatal_exit("%s present twice, cannot bind the same ports twice. The first entry is %s and the second is %s", resif[i][j], info2, info1);
+ }
+ }
+ }
+ }
+ }
+
+ for(i=0; i<cfg->num_ifs; i++) {
+ config_del_strarray(resif[i], num_resif[i]);
}
+ free(resif);
+ free(num_resif);
+
for(i=0; i<cfg->num_out_ifs; i++) {
if(!ipstrtoaddr(cfg->out_ifs[i], UNBOUND_DNS_PORT, &a, &alen) &&
!netblockstrtoaddr(cfg->out_ifs[i], UNBOUND_DNS_PORT, &a, &alen, &d)) {
@@ -909,9 +955,9 @@ int main(int argc, char* argv[])
const char* f;
const char* opt = NULL;
const char* cfgfile = CONFIGFILE;
+ checklock_start();
log_ident_set("unbound-checkconf");
log_init(NULL, 0, NULL);
- checklock_start();
#ifdef USE_WINSOCK
/* use registry config file in preference to compiletime location */
if(!(cfgfile=w_lookup_reg_str("Software\\Unbound", "ConfigFile")))
diff --git a/contrib/unbound/smallapp/unbound-control.c b/contrib/unbound/smallapp/unbound-control.c
index f28875b9c538..0ebbd8305848 100644
--- a/contrib/unbound/smallapp/unbound-control.c
+++ b/contrib/unbound/smallapp/unbound-control.c
@@ -944,9 +944,9 @@ int main(int argc, char* argv[])
extern int check_locking_order;
check_locking_order = 0;
#endif /* USE_THREAD_DEBUG */
+ checklock_start();
log_ident_set("unbound-control");
log_init(NULL, 0, NULL);
- checklock_start();
#ifdef USE_WINSOCK
/* use registry config file in preference to compiletime location */
if(!(cfgfile=w_lookup_reg_str("Software\\Unbound", "ConfigFile")))
diff --git a/contrib/unbound/smallapp/worker_cb.c b/contrib/unbound/smallapp/worker_cb.c
index 473e32a607f8..78e773938c88 100644
--- a/contrib/unbound/smallapp/worker_cb.c
+++ b/contrib/unbound/smallapp/worker_cb.c
@@ -99,7 +99,7 @@ struct outbound_entry* worker_send_query(
int ATTR_UNUSED(dnssec), int ATTR_UNUSED(want_dnssec),
int ATTR_UNUSED(nocaps), struct sockaddr_storage* ATTR_UNUSED(addr),
socklen_t ATTR_UNUSED(addrlen), uint8_t* ATTR_UNUSED(zone),
- size_t ATTR_UNUSED(zonelen), int ATTR_UNUSED(ssl_upstream),
+ size_t ATTR_UNUSED(zonelen), int ATTR_UNUSED(tcp_upstream), int ATTR_UNUSED(ssl_upstream),
char* ATTR_UNUSED(tls_auth_name), struct module_qstate* ATTR_UNUSED(q))
{
log_assert(0);
@@ -131,7 +131,7 @@ struct outbound_entry* libworker_send_query(
int ATTR_UNUSED(dnssec), int ATTR_UNUSED(want_dnssec),
int ATTR_UNUSED(nocaps), struct sockaddr_storage* ATTR_UNUSED(addr),
socklen_t ATTR_UNUSED(addrlen), uint8_t* ATTR_UNUSED(zone),
- size_t ATTR_UNUSED(zonelen), int ATTR_UNUSED(ssl_upstream),
+ size_t ATTR_UNUSED(zonelen), int ATTR_UNUSED(tcp_upstream), int ATTR_UNUSED(ssl_upstream),
char* ATTR_UNUSED(tls_auth_name), struct module_qstate* ATTR_UNUSED(q))
{
log_assert(0);
diff --git a/contrib/unbound/testdata/auth_zonemd_xfr_chain_keyinxfr.rpl b/contrib/unbound/testdata/auth_zonemd_xfr_chain_keyinxfr.rpl
new file mode 100644
index 000000000000..2feec88c075a
--- /dev/null
+++ b/contrib/unbound/testdata/auth_zonemd_xfr_chain_keyinxfr.rpl
@@ -0,0 +1,315 @@
+; config options
+server:
+ target-fetch-policy: "0 0 0 0 0"
+ trust-anchor: "com. DS 1444 8 2 0d72034e3e18a9ef383c164b68302433bbde957616e10cf44575fea2abae469c"
+ trust-anchor-signaling: no
+ val-override-date: 20201020135527
+
+auth-zone:
+ name: "example.com."
+ ## zonefile (or none).
+ ## zonefile: "example.com.zone"
+ ## master by IP address or hostname
+ ## can list multiple masters, each on one line.
+ ## master:
+ master: 1.2.3.44
+ ## url for http fetch
+ ## url:
+ ## queries from downstream clients get authoritative answers.
+ ## for-downstream: yes
+
+ ## The for-downstream and fallback are disabled, the key cannot be
+ ## retrieved by DNS lookup, it is in the xfr itself.
+ ## only after the zone is loaded can it be looked up.
+ for-downstream: no
+ ## queries are used to fetch authoritative answers from this zone,
+ ## instead of unbound itself sending queries there.
+ ## for-upstream: yes
+ for-upstream: yes
+ ## on failures with for-upstream, fallback to sending queries to
+ ## the authority servers
+ ## fallback-enabled: no
+ fallback-enabled: no
+ zonemd-check: yes
+
+ ## this line generates zonefile: \n"/tmp/xxx.example.com"\n
+ zonefile:
+TEMPFILE_NAME example.com
+ ## this is the inline file /tmp/xxx.example.com
+ ## the tempfiles are deleted when the testrun is over.
+TEMPFILE_CONTENTS example.com
+TEMPFILE_END
+
+stub-zone:
+ name: "."
+ stub-addr: 193.0.14.129 # K.ROOT-SERVERS.NET.
+CONFIG_END
+
+SCENARIO_BEGIN Test authority zone with AXFR with ZONEMD with key in xfr
+
+; K.ROOT-SERVERS.NET.
+RANGE_BEGIN 0 100
+ ADDRESS 193.0.14.129
+ENTRY_BEGIN
+MATCH opcode qtype qname
+ADJUST copy_id
+REPLY QR NOERROR
+SECTION QUESTION
+. IN NS
+SECTION ANSWER
+. IN NS K.ROOT-SERVERS.NET.
+SECTION ADDITIONAL
+K.ROOT-SERVERS.NET. IN A 193.0.14.129
+ENTRY_END
+
+ENTRY_BEGIN
+MATCH opcode subdomain
+ADJUST copy_id copy_query
+REPLY QR NOERROR
+SECTION QUESTION
+com. IN NS
+SECTION AUTHORITY
+com. IN NS a.gtld-servers.net.
+SECTION ADDITIONAL
+a.gtld-servers.net. IN A 192.5.6.30
+ENTRY_END
+RANGE_END
+
+; a.gtld-servers.net.
+RANGE_BEGIN 0 100
+ ADDRESS 192.5.6.30
+ENTRY_BEGIN
+MATCH opcode qtype qname
+ADJUST copy_id
+REPLY QR NOERROR
+SECTION QUESTION
+com. IN NS
+SECTION ANSWER
+com. IN NS a.gtld-servers.net.
+SECTION ADDITIONAL
+a.gtld-servers.net. IN A 192.5.6.30
+ENTRY_END
+
+ENTRY_BEGIN
+MATCH opcode qname qtype
+ADJUST copy_id
+REPLY QR AA NOERROR
+SECTION QUESTION
+example.com. IN DS
+SECTION ANSWER
+example.com. 3600 IN DS 55566 8 2 9c148338951ce1c3b5cd3da532f3d90dfcf92595148022f2c2fd98e5deee90af
+example.com. 3600 IN RRSIG DS 8 2 3600 20201116135527 20201019135527 1444 com. BpV1M171SSkbdlGawwweJwQ0W+aNaCrgkt2QTsxCvbo1acR5i3AKm4REOUzo4I36lRx26mYkF9Topkeu0aFmov7P2uUhCxk4faFK7k87k97FAqZaDGp/K9b3YCfiwJBc5pJSUW0ndU/Ve5zAh/wL493RMSC7LwJr5JjV0NxydFk=
+ENTRY_END
+
+ENTRY_BEGIN
+MATCH opcode subdomain
+ADJUST copy_id copy_query
+REPLY QR NOERROR
+SECTION QUESTION
+example.com. IN NS
+SECTION AUTHORITY
+example.com. IN NS ns.example.com.
+example.com. 3600 IN DS 55566 8 2 9c148338951ce1c3b5cd3da532f3d90dfcf92595148022f2c2fd98e5deee90af
+example.com. 3600 IN RRSIG DS 8 2 3600 20201116135527 20201019135527 1444 com. BpV1M171SSkbdlGawwweJwQ0W+aNaCrgkt2QTsxCvbo1acR5i3AKm4REOUzo4I36lRx26mYkF9Topkeu0aFmov7P2uUhCxk4faFK7k87k97FAqZaDGp/K9b3YCfiwJBc5pJSUW0ndU/Ve5zAh/wL493RMSC7LwJr5JjV0NxydFk=
+SECTION ADDITIONAL
+ns.example.com. IN A 1.2.3.44
+ENTRY_END
+
+ENTRY_BEGIN
+MATCH opcode qtype qname
+ADJUST copy_id
+REPLY QR AA NOERROR
+SECTION QUESTION
+com. IN DNSKEY
+SECTION ANSWER
+com. 3600 IN DNSKEY 257 3 8 AwEAAbd9WqjzE2Pynz21OG5doSf9hFzMr5dhzz2waZ3vTa+0o5r7AjTAqmA1yH/B3+aAMihUm5ucZSfVqo7+kOaRE8yFj9aivOmA1n1+JLevJq/oyvQyjxQN2Qb89LyaNUT5oKZIiL+uyyhNW3KDR3SSbQ/GBwQNDHVcZi+JDR3RC0r7 ;{id = 1444 (ksk), size = 1024b}
+com. 3600 IN RRSIG DNSKEY 8 1 3600 20201116135527 20201019135527 1444 com. BEOMfWvi6RgnHaHsst+Ed265hBuCkgMR7gDpu89J7ZrVL6DzMKnNVFdgjl/9xwLj/pkukc7qeLSHjAfLlN0E4THW7PVshscQnjvXCkktG2Ejx9fTyllAqeGDh9z9QDGlQZIGTMgb9413qZhNqe2Tda9PTJRpiZ8b4bdQp6V1kVo=
+SECTION ADDITIONAL
+ENTRY_END
+RANGE_END
+
+; ns.example.net.
+RANGE_BEGIN 0 100
+ ADDRESS 1.2.3.44
+ENTRY_BEGIN
+MATCH opcode qtype qname
+ADJUST copy_id
+REPLY QR NOERROR
+SECTION QUESTION
+example.net. IN NS
+SECTION ANSWER
+example.net. IN NS ns.example.net.
+SECTION ADDITIONAL
+ns.example.net. IN A 1.2.3.44
+ENTRY_END
+
+ENTRY_BEGIN
+MATCH opcode qtype qname
+ADJUST copy_id
+REPLY QR NOERROR
+SECTION QUESTION
+ns.example.net. IN A
+SECTION ANSWER
+ns.example.net. IN A 1.2.3.44
+SECTION AUTHORITY
+example.net. IN NS ns.example.net.
+ENTRY_END
+
+ENTRY_BEGIN
+MATCH opcode qtype qname
+ADJUST copy_id
+REPLY QR NOERROR
+SECTION QUESTION
+ns.example.net. IN AAAA
+SECTION AUTHORITY
+example.net. IN NS ns.example.net.
+SECTION ADDITIONAL
+www.example.net. IN A 1.2.3.44
+ENTRY_END
+
+ENTRY_BEGIN
+MATCH opcode qtype qname
+ADJUST copy_id
+REPLY QR NOERROR
+SECTION QUESTION
+example.com. IN NS
+SECTION ANSWER
+example.com. IN NS ns.example.net.
+ENTRY_END
+
+ENTRY_BEGIN
+MATCH opcode qtype qname
+ADJUST copy_id
+REPLY QR NOERROR
+SECTION QUESTION
+www.example.com. IN A
+SECTION ANSWER
+www.example.com. IN A 10.20.30.40
+ENTRY_END
+
+ENTRY_BEGIN
+MATCH opcode qtype qname
+ADJUST copy_id
+REPLY QR NOERROR
+SECTION QUESTION
+example.com. IN SOA
+SECTION ANSWER
+; serial, refresh, retry, expire, minimum
+example.com. IN SOA ns.example.com. hostmaster.example.com. 1 3600 900 86400 3600
+ENTRY_END
+
+ENTRY_BEGIN
+MATCH opcode qtype qname
+ADJUST copy_id
+REPLY QR AA NOERROR
+SECTION QUESTION
+example.com. IN AXFR
+SECTION ANSWER
+example.com. 3600 IN SOA ns.example.com. hostmaster.example.com. 200154054 28800 7200 604800 3600
+example.com. 3600 IN RRSIG SOA 8 2 3600 20201116135527 20201019135527 55566 example.com. gcFHT/Q4iDZ78CK6fyY2HZr8sRtgH2Rna9fEs06RW0gqMnfDntweoIaBamOZ7NlAP84aY2bZeanmEccmkHexByUpodCoKQ4NzVXctLr0TO4PVoFyfUfj62fjhM56SF8ioDxsoDQcPtYXcjNQjwfntWofMqHCMxrb9LzbgePzhOM=
+example.com. 3600 IN NS ns.example.com.
+example.com. 3600 IN RRSIG NS 8 2 3600 20201116135527 20201019135527 55566 example.com. X+V3XsbJbBi9OsHpjMkGCox8RLY/uXp/XX/O/flTrIre9fMDWm9ZGnewtuQFpLgGc6hUTi0eLsuRWRA5fZXEKUBhmoR2Ph01KgE1gvlL7v6zPWQwXVcBRUr3mOSbYdNNkHkXEjiDBGEhNkfqR216zNgw563eEGXOkLUFNIx5Zpg=
+example.com. 3600 IN DNSKEY 256 3 8 AwEAAdug/L739i0mgN2nuK/bhxu3wFn5Ud9nK2+XUmZQlPUEZUC5YZvm1rfMmEWTGBn87fFxEu/kjFZHJ55JLzqsbbpVHLbmKCTT2gYR2FV2WDKROGKuYbVkJIXdKAjJ0ONuK507NinYvlWXIoxHn22KAWOd9wKgSTNHBlmGkX+ts3hh ;{id = 55566 (zsk), size = 1024b}
+example.com. 3600 IN RRSIG DNSKEY 8 2 3600 20201116135527 20201019135527 55566 example.com. fsdnVg38PKQTH2mDOwkXL6Jre7JP7Gf8WI3CvIbmeYQUJtAlpcSbZkS3wInm3kKMxOuT55BWzndQzpfmpo91OqJjG27W0k9301NMLUwFprA6b9HK+iPAT0JpYPDPzcm1bQdarLzLS+eD/GPwmyVSX7Gze+08VfE8m8sOW2r7UjA=
+example.com. 3600 IN TYPE63 \# 70 0bee1bc6010258f7620f93204bbb31b44f795b3409cc4abd9ef5601decc15675bd7751213152984eddce0626e6062e744b03b3e47711202fbb79e4a2eb8bc5cf46741b5cae6f
+example.com. 3600 IN RRSIG TYPE63 8 2 3600 20201116135527 20201019135527 55566 example.com. orn8ZF/yqj9u4WrhiO6gtEcTaVsnZSWWZLfXhcIOiWSB8kKCxtZl5cG17dD3Du1NllUwMRqkp0KleLhIoUS9xeQ/0x05u+CYLrfQ62oAiD7q54ZQzpXJIH52aQzKV70ZnO03CZowhQBnetmIoKX6xLogKo8pt+BdQbo3oVHxV8Y=
+example.com. 3600 IN NSEC bar.example.com. NS SOA RRSIG NSEC DNSKEY TYPE63
+example.com. 3600 IN RRSIG NSEC 8 2 3600 20201116135527 20201019135527 55566 example.com. ufLrlOQprAqjnH85Rt3T0Mxd3ZB0mBeeNIr84eFJ8Rk6WiWEPm0Y1R7GRufNI24Mj7iqLcL4nJM6KK6B7dJqjqu73jw1acuYNnbsoV2BNDRXRFP2FNWTpctVdi+955f3FzgsmEJXfGiSUG0YXAEcZmdCPCn5ii2jk8mk7r6KKYo=
+bar.example.com. 3600 IN A 1.2.3.4
+bar.example.com. 3600 IN RRSIG A 8 3 3600 20201116135527 20201019135527 55566 example.com. NYhmRicF4C9+YxpWeQrepy4ALM1CM0USoDuGi3W5Xtp4/+YpCJfSIdR9vlJaJ2WayYuZrz9Ai2ci7oWwE1Fn3oywGwCKvGo9m0c3mC2eEtphE19wrop6pWu6um4RiFhmzYS1voraA3PAdYzze9U4NHzlk0+sb5vNZW9dSZS30Ds=
+bar.example.com. 3600 IN NSEC ding.example.com. A RRSIG NSEC
+bar.example.com. 3600 IN RRSIG NSEC 8 3 3600 20201116135527 20201019135527 55566 example.com. VhsGuBx20DXQZNU8ITAMnasn6NVyEjN9xtB8msH5xJn80UCuaqvFBURzcPWN3aHnykEvGfdPF/9P3WvlON0cMikWkqSLy6Q9bpvgAq13HWYh+ZcDoqLtICaB7RkBQc+6aHAqZFyQbD8/m8Kxt5eVJtV6rEuf+yPX0+3aXHhsRg0=
+ding.example.com. 3600 IN A 1.2.3.4
+ding.example.com. 3600 IN RRSIG A 8 3 3600 20201116135527 20201019135527 55566 example.com. OERsruISkpd1s68ute8Xm8YXisBCTkkiDMt34K+0dVqvySOJq63d3qN18BeUxZxLyHDB1eR3nZZKqEdkTqrv2r98skhWhjnOECpFbu5gKjtN/KPexbbJ+rxC0QqciuWOC7M6YE0cvI17/RB9KhVRy5rqY2X4Gt2wk2CNeD1dAko=
+ding.example.com. 3600 IN NSEC foo.example.com. A RRSIG NSEC
+ding.example.com. 3600 IN RRSIG NSEC 8 3 3600 20201116135527 20201019135527 55566 example.com. nb1W2aaKrU5iAQiY8gMsoMOejID19JMTEwY2rRoe+KsvzMs0rE0ifEkqit4blXaU0tfy0foJ70uqdJFqBoGz1NcSwZ6GNk/iNfGvG3XpxZ/zqEe7kkIucqqei794G7z9psqV94yZ3WaT+IswPpWrSaWv1w41RtcWufPhe4fOAmU=
+foo.example.com. 3600 IN A 1.2.3.4
+foo.example.com. 3600 IN RRSIG A 8 3 3600 20201116135527 20201019135527 55566 example.com. ZcUngb2pUejwnsshbJN/Dfr+Bzu8fcZXyqLArQ+10Bw1IPHyfx7yyUJ43V5tTYVHPSEsJzTnaWj+olVrNhVZxq5e0pgzSYPfGln2FEItEvMIOn33j8yKTpPW2MLyuFF5ZkXhosG20EUwRMvMmRHRz9mIZfwWoMbSGPukmLh8zMA=
+foo.example.com. 3600 IN NSEC ns.example.com. A RRSIG NSEC
+foo.example.com. 3600 IN RRSIG NSEC 8 3 3600 20201116135527 20201019135527 55566 example.com. fUZEpkEULRWDntN5Z7Kr8M83Hjhf08ECMKRpo6IBoBc3ayenj+YMgWAvFXC825wjENPYYWNGag0d32U83zCZxqgv+8uXZd3B7QDpTbL41aWZdc++s5YWTkYjyOWwJ1XHOv4nL3qEnJBXVzo/E1gbSKhTFuG97i+7J1MFd9MsC5s=
+ns.example.com. 3600 IN A 127.0.0.1
+ns.example.com. 3600 IN RRSIG A 8 3 3600 20201116135527 20201019135527 55566 example.com. SiuxuPtN/ITd+Z20j8UNUHJWbLHirE8zQOWMv5fAZ1rPKpAidrZgUL8J417GdrTwkueU2ywAJ7EzFJSwNTa7o/wUnq7svmOR6Ze6UQsKuZFZGEfqPNDRp4YuF86LU5jChuo+f/IRpydHrxVwGxDPCR9KarDM+ewfW+yI5bZeZcg=
+ns.example.com. 3600 IN NSEC www.example.com. A RRSIG NSEC
+ns.example.com. 3600 IN RRSIG NSEC 8 3 3600 20201116135527 20201019135527 55566 example.com. 0upKNYjiow4NDJm3I1RbUddE9GGuFYEVKswww5BAc/6WHuukupncL30lskvcSKGpByDssP2Hi2CufyEtYeGWh6q1TxtOFRqFBX1p6Q5b3tBlCtvv4h31dQR9uqLvq+GkGS5MR+0LO5kWagIpZmnI8YY5plVdXEtNbp2Ar8zvz/A=
+www.example.com. 3600 IN A 127.0.0.1
+www.example.com. 3600 IN RRSIG A 8 3 3600 20201116135527 20201019135527 55566 example.com. AaIeICaPjV50TDrpbyOn94+hs8EYIMTmN4pYqj7e8GIGimqQIk5jgpwSx6SOoOF+uOqkf9GKHkQTn5YVGaeXwEQleg7mPTmMYKAOk06Y7MFUO1Vwt1Vt7Wo+Cpa3x2a1CmEkfFOi4WqP43VJnUtjjKmXoKRz3VUmqByyJYUAGbQ=
+www.example.com. 3600 IN NSEC example.com. A RRSIG NSEC
+www.example.com. 3600 IN RRSIG NSEC 8 3 3600 20201116135527 20201019135527 55566 example.com. meg/t6nIBqQZ0d5/dT7uu/3CuP4vE+HxqFQaj2fjUNceA/6C7QIQnqQ5Kyblg+XijDkQX0yvyFNHYdgF16UDgFT7tlNUCHk1SpF5BWzV4c4tBEhxASTz7UQo111O3Tyd6CldPzO/Se15Ud0/ZYltHEqWTfY5nJoXC/OJD9V2QOI=
+example.com. 3600 IN SOA ns.example.com. hostmaster.example.com. 200154054 28800 7200 604800 3600
+ENTRY_END
+RANGE_END
+
+STEP 1 QUERY
+ENTRY_BEGIN
+REPLY RD
+SECTION QUESTION
+www.example.com. IN A
+ENTRY_END
+
+; recursion happens here.
+STEP 20 CHECK_ANSWER
+ENTRY_BEGIN
+MATCH all
+REPLY QR RD RA SERVFAIL
+SECTION QUESTION
+www.example.com. IN A
+SECTION ANSWER
+ENTRY_END
+
+STEP 30 TIME_PASSES ELAPSE 10
+STEP 40 TRAFFIC
+
+STEP 50 QUERY
+ENTRY_BEGIN
+REPLY RD
+SECTION QUESTION
+www.example.com. IN A
+ENTRY_END
+
+; recursion happens here.
+STEP 60 CHECK_ANSWER
+ENTRY_BEGIN
+MATCH all
+REPLY QR RD RA NOERROR
+SECTION QUESTION
+www.example.com. IN A
+SECTION ANSWER
+www.example.com. IN A 127.0.0.1
+ENTRY_END
+
+; the zonefile was updated with new contents
+STEP 70 CHECK_TEMPFILE example.com
+FILE_BEGIN
+example.com. 3600 IN SOA ns.example.com. hostmaster.example.com. 200154054 28800 7200 604800 3600
+example.com. 3600 IN RRSIG SOA 8 2 3600 20201116135527 20201019135527 55566 example.com. gcFHT/Q4iDZ78CK6fyY2HZr8sRtgH2Rna9fEs06RW0gqMnfDntweoIaBamOZ7NlAP84aY2bZeanmEccmkHexByUpodCoKQ4NzVXctLr0TO4PVoFyfUfj62fjhM56SF8ioDxsoDQcPtYXcjNQjwfntWofMqHCMxrb9LzbgePzhOM=
+example.com. 3600 IN NS ns.example.com.
+example.com. 3600 IN RRSIG NS 8 2 3600 20201116135527 20201019135527 55566 example.com. X+V3XsbJbBi9OsHpjMkGCox8RLY/uXp/XX/O/flTrIre9fMDWm9ZGnewtuQFpLgGc6hUTi0eLsuRWRA5fZXEKUBhmoR2Ph01KgE1gvlL7v6zPWQwXVcBRUr3mOSbYdNNkHkXEjiDBGEhNkfqR216zNgw563eEGXOkLUFNIx5Zpg=
+example.com. 3600 IN NSEC bar.example.com. NS SOA RRSIG NSEC DNSKEY ZONEMD
+example.com. 3600 IN RRSIG NSEC 8 2 3600 20201116135527 20201019135527 55566 example.com. ufLrlOQprAqjnH85Rt3T0Mxd3ZB0mBeeNIr84eFJ8Rk6WiWEPm0Y1R7GRufNI24Mj7iqLcL4nJM6KK6B7dJqjqu73jw1acuYNnbsoV2BNDRXRFP2FNWTpctVdi+955f3FzgsmEJXfGiSUG0YXAEcZmdCPCn5ii2jk8mk7r6KKYo=
+example.com. 3600 IN DNSKEY 256 3 8 AwEAAdug/L739i0mgN2nuK/bhxu3wFn5Ud9nK2+XUmZQlPUEZUC5YZvm1rfMmEWTGBn87fFxEu/kjFZHJ55JLzqsbbpVHLbmKCTT2gYR2FV2WDKROGKuYbVkJIXdKAjJ0ONuK507NinYvlWXIoxHn22KAWOd9wKgSTNHBlmGkX+ts3hh ;{id = 55566}
+example.com. 3600 IN RRSIG DNSKEY 8 2 3600 20201116135527 20201019135527 55566 example.com. fsdnVg38PKQTH2mDOwkXL6Jre7JP7Gf8WI3CvIbmeYQUJtAlpcSbZkS3wInm3kKMxOuT55BWzndQzpfmpo91OqJjG27W0k9301NMLUwFprA6b9HK+iPAT0JpYPDPzcm1bQdarLzLS+eD/GPwmyVSX7Gze+08VfE8m8sOW2r7UjA=
+example.com. 3600 IN ZONEMD 200154054 1 2 58F7620F93204BBB31B44F795B3409CC4ABD9EF5601DECC15675BD7751213152984EDDCE0626E6062E744B03B3E47711202FBB79E4A2EB8BC5CF46741B5CAE6F
+example.com. 3600 IN RRSIG ZONEMD 8 2 3600 20201116135527 20201019135527 55566 example.com. orn8ZF/yqj9u4WrhiO6gtEcTaVsnZSWWZLfXhcIOiWSB8kKCxtZl5cG17dD3Du1NllUwMRqkp0KleLhIoUS9xeQ/0x05u+CYLrfQ62oAiD7q54ZQzpXJIH52aQzKV70ZnO03CZowhQBnetmIoKX6xLogKo8pt+BdQbo3oVHxV8Y=
+bar.example.com. 3600 IN A 1.2.3.4
+bar.example.com. 3600 IN RRSIG A 8 3 3600 20201116135527 20201019135527 55566 example.com. NYhmRicF4C9+YxpWeQrepy4ALM1CM0USoDuGi3W5Xtp4/+YpCJfSIdR9vlJaJ2WayYuZrz9Ai2ci7oWwE1Fn3oywGwCKvGo9m0c3mC2eEtphE19wrop6pWu6um4RiFhmzYS1voraA3PAdYzze9U4NHzlk0+sb5vNZW9dSZS30Ds=
+bar.example.com. 3600 IN NSEC ding.example.com. A RRSIG NSEC
+bar.example.com. 3600 IN RRSIG NSEC 8 3 3600 20201116135527 20201019135527 55566 example.com. VhsGuBx20DXQZNU8ITAMnasn6NVyEjN9xtB8msH5xJn80UCuaqvFBURzcPWN3aHnykEvGfdPF/9P3WvlON0cMikWkqSLy6Q9bpvgAq13HWYh+ZcDoqLtICaB7RkBQc+6aHAqZFyQbD8/m8Kxt5eVJtV6rEuf+yPX0+3aXHhsRg0=
+ding.example.com. 3600 IN A 1.2.3.4
+ding.example.com. 3600 IN RRSIG A 8 3 3600 20201116135527 20201019135527 55566 example.com. OERsruISkpd1s68ute8Xm8YXisBCTkkiDMt34K+0dVqvySOJq63d3qN18BeUxZxLyHDB1eR3nZZKqEdkTqrv2r98skhWhjnOECpFbu5gKjtN/KPexbbJ+rxC0QqciuWOC7M6YE0cvI17/RB9KhVRy5rqY2X4Gt2wk2CNeD1dAko=
+ding.example.com. 3600 IN NSEC foo.example.com. A RRSIG NSEC
+ding.example.com. 3600 IN RRSIG NSEC 8 3 3600 20201116135527 20201019135527 55566 example.com. nb1W2aaKrU5iAQiY8gMsoMOejID19JMTEwY2rRoe+KsvzMs0rE0ifEkqit4blXaU0tfy0foJ70uqdJFqBoGz1NcSwZ6GNk/iNfGvG3XpxZ/zqEe7kkIucqqei794G7z9psqV94yZ3WaT+IswPpWrSaWv1w41RtcWufPhe4fOAmU=
+foo.example.com. 3600 IN A 1.2.3.4
+foo.example.com. 3600 IN RRSIG A 8 3 3600 20201116135527 20201019135527 55566 example.com. ZcUngb2pUejwnsshbJN/Dfr+Bzu8fcZXyqLArQ+10Bw1IPHyfx7yyUJ43V5tTYVHPSEsJzTnaWj+olVrNhVZxq5e0pgzSYPfGln2FEItEvMIOn33j8yKTpPW2MLyuFF5ZkXhosG20EUwRMvMmRHRz9mIZfwWoMbSGPukmLh8zMA=
+foo.example.com. 3600 IN NSEC ns.example.com. A RRSIG NSEC
+foo.example.com. 3600 IN RRSIG NSEC 8 3 3600 20201116135527 20201019135527 55566 example.com. fUZEpkEULRWDntN5Z7Kr8M83Hjhf08ECMKRpo6IBoBc3ayenj+YMgWAvFXC825wjENPYYWNGag0d32U83zCZxqgv+8uXZd3B7QDpTbL41aWZdc++s5YWTkYjyOWwJ1XHOv4nL3qEnJBXVzo/E1gbSKhTFuG97i+7J1MFd9MsC5s=
+ns.example.com. 3600 IN A 127.0.0.1
+ns.example.com. 3600 IN RRSIG A 8 3 3600 20201116135527 20201019135527 55566 example.com. SiuxuPtN/ITd+Z20j8UNUHJWbLHirE8zQOWMv5fAZ1rPKpAidrZgUL8J417GdrTwkueU2ywAJ7EzFJSwNTa7o/wUnq7svmOR6Ze6UQsKuZFZGEfqPNDRp4YuF86LU5jChuo+f/IRpydHrxVwGxDPCR9KarDM+ewfW+yI5bZeZcg=
+ns.example.com. 3600 IN NSEC www.example.com. A RRSIG NSEC
+ns.example.com. 3600 IN RRSIG NSEC 8 3 3600 20201116135527 20201019135527 55566 example.com. 0upKNYjiow4NDJm3I1RbUddE9GGuFYEVKswww5BAc/6WHuukupncL30lskvcSKGpByDssP2Hi2CufyEtYeGWh6q1TxtOFRqFBX1p6Q5b3tBlCtvv4h31dQR9uqLvq+GkGS5MR+0LO5kWagIpZmnI8YY5plVdXEtNbp2Ar8zvz/A=
+www.example.com. 3600 IN A 127.0.0.1
+www.example.com. 3600 IN RRSIG A 8 3 3600 20201116135527 20201019135527 55566 example.com. AaIeICaPjV50TDrpbyOn94+hs8EYIMTmN4pYqj7e8GIGimqQIk5jgpwSx6SOoOF+uOqkf9GKHkQTn5YVGaeXwEQleg7mPTmMYKAOk06Y7MFUO1Vwt1Vt7Wo+Cpa3x2a1CmEkfFOi4WqP43VJnUtjjKmXoKRz3VUmqByyJYUAGbQ=
+www.example.com. 3600 IN NSEC example.com. A RRSIG NSEC
+www.example.com. 3600 IN RRSIG NSEC 8 3 3600 20201116135527 20201019135527 55566 example.com. meg/t6nIBqQZ0d5/dT7uu/3CuP4vE+HxqFQaj2fjUNceA/6C7QIQnqQ5Kyblg+XijDkQX0yvyFNHYdgF16UDgFT7tlNUCHk1SpF5BWzV4c4tBEhxASTz7UQo111O3Tyd6CldPzO/Se15Ud0/ZYltHEqWTfY5nJoXC/OJD9V2QOI=
+FILE_END
+
+SCENARIO_END
diff --git a/contrib/unbound/testdata/fwd_error_retries.rpl b/contrib/unbound/testdata/fwd_error_retries.rpl
new file mode 100644
index 000000000000..b63086c0f46a
--- /dev/null
+++ b/contrib/unbound/testdata/fwd_error_retries.rpl
@@ -0,0 +1,27 @@
+; config options
+server:
+ outbound-msg-retry: 1
+
+forward-zone:
+ name: "."
+ forward-addr: 216.0.0.1
+CONFIG_END
+SCENARIO_BEGIN Test basic forwarding with servfail and retry of 1
+STEP 1 QUERY
+ENTRY_BEGIN
+REPLY RD
+SECTION QUESTION
+www.example.com. IN A
+ENTRY_END
+; query fails with servfail, now we make only outgoing-msg-retry=1 retries
+STEP 2 ERROR
+; returns servfail
+STEP 14 CHECK_ANSWER
+ENTRY_BEGIN
+MATCH opcode qname qtype
+SECTION QUESTION
+REPLY SERVFAIL QR RD RA
+MATCH all
+www.example.com. IN A
+ENTRY_END
+SCENARIO_END
diff --git a/contrib/unbound/testdata/fwd_udp_with_tcp_upstream.tdir/fwd_udp_with_tcp_upstream.conf b/contrib/unbound/testdata/fwd_udp_with_tcp_upstream.tdir/fwd_udp_with_tcp_upstream.conf
new file mode 100644
index 000000000000..6daf2eeecc36
--- /dev/null
+++ b/contrib/unbound/testdata/fwd_udp_with_tcp_upstream.tdir/fwd_udp_with_tcp_upstream.conf
@@ -0,0 +1,20 @@
+server:
+ verbosity: 5
+ # num-threads: 1
+ interface: 127.0.0.1
+ port: @PORT@
+ use-syslog: no
+ directory: ""
+ pidfile: "unbound.pid"
+ chroot: ""
+ username: ""
+ do-not-query-localhost: no
+forward-zone:
+ name: "tcp.example.com"
+ forward-addr: "127.0.0.1@@TOPORT@"
+ forward-tcp-upstream: "yes"
+forward-zone:
+ name: "udp.example.com"
+ forward-addr: "127.0.0.1@@TOPORT@"
+ forward-tcp-upstream: "no"
+
diff --git a/contrib/unbound/testdata/fwd_udp_with_tcp_upstream.tdir/fwd_udp_with_tcp_upstream.dsc b/contrib/unbound/testdata/fwd_udp_with_tcp_upstream.tdir/fwd_udp_with_tcp_upstream.dsc
new file mode 100644
index 000000000000..5b1f0d3d1ab4
--- /dev/null
+++ b/contrib/unbound/testdata/fwd_udp_with_tcp_upstream.tdir/fwd_udp_with_tcp_upstream.dsc
@@ -0,0 +1,16 @@
+BaseName: fwd_udp_with_tcp_upstream
+Version: 1.0
+Description: Forward an UDP packet to upstream via TCP and return reply.
+CreationDate: Thu Aug 5 07:44:41 CEST 2021
+Maintainer: ziollek
+Category:
+Component:
+CmdDepends:
+Depends:
+Help:
+Pre: fwd_udp_with_tcp_upstream.pre
+Post: fwd_udp_with_tcp_upstream.post
+Test: fwd_udp_with_tcp_upstream.test
+AuxFiles:
+Passed:
+Failure:
diff --git a/contrib/unbound/testdata/fwd_udp_with_tcp_upstream.tdir/fwd_udp_with_tcp_upstream.post b/contrib/unbound/testdata/fwd_udp_with_tcp_upstream.tdir/fwd_udp_with_tcp_upstream.post
new file mode 100644
index 000000000000..0013eca71a4d
--- /dev/null
+++ b/contrib/unbound/testdata/fwd_udp_with_tcp_upstream.tdir/fwd_udp_with_tcp_upstream.post
@@ -0,0 +1,10 @@
+# #-- fwd_udp_with_tcp_upstream.post --#
+# source the master var file when it's there
+[ -f ../.tpkg.var.master ] && source ../.tpkg.var.master
+# source the test var file when it's there
+[ -f .tpkg.var.test ] && source .tpkg.var.test
+#
+# do your teardown here
+. ../common.sh
+kill_pid $FWD_PID
+kill_pid $UNBOUND_PID
diff --git a/contrib/unbound/testdata/fwd_udp_with_tcp_upstream.tdir/fwd_udp_with_tcp_upstream.pre b/contrib/unbound/testdata/fwd_udp_with_tcp_upstream.tdir/fwd_udp_with_tcp_upstream.pre
new file mode 100644
index 000000000000..546787a5fc9f
--- /dev/null
+++ b/contrib/unbound/testdata/fwd_udp_with_tcp_upstream.tdir/fwd_udp_with_tcp_upstream.pre
@@ -0,0 +1,31 @@
+# #-- fwd_udp_with_tcp_upstream.pre--#
+# source the master var file when it's there
+[ -f ../.tpkg.var.master ] && source ../.tpkg.var.master
+# use .tpkg.var.test for in test variable passing
+[ -f .tpkg.var.test ] && source .tpkg.var.test
+
+. ../common.sh
+get_random_port 2
+UNBOUND_PORT=$RND_PORT
+FWD_PORT=$(($RND_PORT + 1))
+echo "UNBOUND_PORT=$UNBOUND_PORT" >> .tpkg.var.test
+echo "FWD_PORT=$FWD_PORT" >> .tpkg.var.test
+
+# start forwarder
+get_ldns_testns
+$LDNS_TESTNS -p $FWD_PORT fwd_udp_with_tcp_upstream.testns >fwd.log 2>&1 &
+FWD_PID=$!
+echo "FWD_PID=$FWD_PID" >> .tpkg.var.test
+
+# make config file
+sed -e 's/@PORT\@/'$UNBOUND_PORT'/' -e 's/@TOPORT\@/'$FWD_PORT'/' < fwd_udp_with_tcp_upstream.conf > ub.conf
+# start unbound in the background
+PRE="../.."
+$PRE/unbound -d -c ub.conf >unbound.log 2>&1 &
+UNBOUND_PID=$!
+echo "UNBOUND_PID=$UNBOUND_PID" >> .tpkg.var.test
+
+cat .tpkg.var.test
+wait_ldns_testns_up fwd.log
+wait_unbound_up unbound.log
+
diff --git a/contrib/unbound/testdata/fwd_udp_with_tcp_upstream.tdir/fwd_udp_with_tcp_upstream.test b/contrib/unbound/testdata/fwd_udp_with_tcp_upstream.tdir/fwd_udp_with_tcp_upstream.test
new file mode 100644
index 000000000000..fad6497beb15
--- /dev/null
+++ b/contrib/unbound/testdata/fwd_udp_with_tcp_upstream.tdir/fwd_udp_with_tcp_upstream.test
@@ -0,0 +1,35 @@
+# #-- fwd_udp_with_tcp_upstream.test --#
+# source the master var file when it's there
+[ -f ../.tpkg.var.master ] && source ../.tpkg.var.master
+# use .tpkg.var.test for in test variable passing
+[ -f .tpkg.var.test ] && source .tpkg.var.test
+
+PRE="../.."
+# do the test
+echo "> dig tcp.example.com."
+dig @localhost -p $UNBOUND_PORT tcp.example.com. | tee outfile
+echo "> cat logfiles"
+cat fwd.log
+cat unbound.log
+echo "> check answer"
+if grep "10.20.30.40" outfile; then
+ echo "OK"
+else
+ echo "Not OK"
+ exit 1
+fi
+
+echo "> dig udp.example.com."
+dig @localhost -p $UNBOUND_PORT udp.example.com. | tee outfile
+echo "> cat logfiles"
+cat fwd.log
+cat unbound.log
+echo "> check answer"
+if grep "10.20.30.80" outfile; then
+ echo "OK"
+else
+ echo "Not OK"
+ exit 1
+fi
+
+exit 0
diff --git a/contrib/unbound/testdata/fwd_udp_with_tcp_upstream.tdir/fwd_udp_with_tcp_upstream.testns b/contrib/unbound/testdata/fwd_udp_with_tcp_upstream.tdir/fwd_udp_with_tcp_upstream.testns
new file mode 100644
index 000000000000..04089af0e1b6
--- /dev/null
+++ b/contrib/unbound/testdata/fwd_udp_with_tcp_upstream.tdir/fwd_udp_with_tcp_upstream.testns
@@ -0,0 +1,25 @@
+; nameserver test file
+$ORIGIN example.com.
+$TTL 3600
+
+ENTRY_BEGIN
+MATCH opcode qtype qname
+MATCH TCP
+REPLY QR AA NOERROR
+ADJUST copy_id
+SECTION QUESTION
+tcp IN A
+SECTION ANSWER
+tcp IN A 10.20.30.40
+ENTRY_END
+
+ENTRY_BEGIN
+MATCH opcode qtype qname
+MATCH UDP
+REPLY QR AA NOERROR
+ADJUST copy_id
+SECTION QUESTION
+udp IN A
+SECTION ANSWER
+udp IN A 10.20.30.80
+ENTRY_END
diff --git a/contrib/unbound/testdata/http_user_agent.tdir/http_user_agent.test b/contrib/unbound/testdata/http_user_agent.tdir/http_user_agent.test
index afc0fbbe6f4b..dce2d476c8f6 100644
--- a/contrib/unbound/testdata/http_user_agent.tdir/http_user_agent.test
+++ b/contrib/unbound/testdata/http_user_agent.tdir/http_user_agent.test
@@ -81,12 +81,12 @@ echo "> cat logfiles"
cat petal.log
cat unbound.log
-# check petal.log for the correct number of occurences.
+# check petal.log for the correct number of occurrences.
# It should be 2 User-Agents, one being the custom.
-echo "> check User-Agent occurences"
-occurences=`grep "User-Agent:" petal.log | wc -l`
-echo $occurences
-if test $occurences -eq 2; then
+echo "> check User-Agent occurrences"
+occurrences=`grep "User-Agent:" petal.log | wc -l`
+echo $occurrences
+if test $occurrences -eq 2; then
echo "OK"
else
echo "Not OK"
diff --git a/contrib/unbound/testdata/rpz_clientip.rpl b/contrib/unbound/testdata/rpz_clientip.rpl
new file mode 100644
index 000000000000..78e05ad91994
--- /dev/null
+++ b/contrib/unbound/testdata/rpz_clientip.rpl
@@ -0,0 +1,264 @@
+; config options
+server:
+ module-config: "respip validator iterator"
+ target-fetch-policy: "0 0 0 0 0"
+ qname-minimisation: no
+ minimal-responses: no
+ access-control: 192.0.0.0/8 allow
+
+rpz:
+ name: "rpz.example.com."
+ zonefile:
+TEMPFILE_NAME rpz.example.com
+TEMPFILE_CONTENTS rpz.example.com
+$ORIGIN example.com.
+rpz 3600 IN SOA ns1.rpz.example.com. hostmaster.rpz.example.com. (
+ 1379078166 28800 7200 604800 7200 )
+ 3600 IN NS ns1.rpz.example.com.
+ 3600 IN NS ns2.rpz.example.com.
+$ORIGIN rpz.example.com.
+24.0.0.0.192.rpz-client-ip CNAME .
+24.0.1.0.192.rpz-client-ip CNAME *.
+24.0.2.0.192.rpz-client-ip CNAME rpz-drop.
+24.0.3.0.192.rpz-client-ip CNAME rpz-passthru.
+24.0.4.0.192.rpz-client-ip CNAME rpz-tcp-only.
+24.0.5.0.192.rpz-client-ip A 127.0.0.1
+24.0.5.0.192.rpz-client-ip TXT "42"
+TEMPFILE_END
+
+stub-zone:
+ name: "a."
+ stub-addr: 10.20.30.40
+CONFIG_END
+
+SCENARIO_BEGIN Test RPZ client ip triggers
+
+RANGE_BEGIN 0 100
+ ADDRESS 10.20.30.40
+ENTRY_BEGIN
+MATCH opcode qtype qname
+ADJUST copy_id
+REPLY QR NOERROR
+SECTION QUESTION
+a. IN NS
+SECTION ANSWER
+a. IN NS ns.a.
+SECTION ADDITIONAL
+ns.a IN A 10.20.30.40
+ENTRY_END
+
+ENTRY_BEGIN
+MATCH opcode qtype qname
+ADJUST copy_id
+REPLY QR NOERROR
+SECTION QUESTION
+a.a. IN TXT
+SECTION ANSWER
+a.a. IN TXT "upstream txt rr a.a."
+ENTRY_END
+
+ENTRY_BEGIN
+MATCH opcode qtype qname
+ADJUST copy_id
+REPLY QR NOERROR
+SECTION QUESTION
+a.a. IN A
+SECTION ANSWER
+a.a. IN A 10.20.30.40
+ENTRY_END
+
+ENTRY_BEGIN
+MATCH opcode qtype qname
+ADJUST copy_id
+REPLY QR NOERROR
+SECTION QUESTION
+a.a. IN AAAA
+SECTION ANSWER
+a.a. IN AAAA 2001:db8::123
+ENTRY_END
+
+RANGE_END
+
+; unrelated client ip address -- passthru
+
+STEP 10 QUERY
+ENTRY_BEGIN
+REPLY RD
+SECTION QUESTION
+a.a. IN TXT
+ENTRY_END
+
+STEP 11 CHECK_ANSWER
+ENTRY_BEGIN
+MATCH all
+REPLY QR RD RA NOERROR
+SECTION QUESTION
+a.a. IN TXT
+SECTION ANSWER
+a.a. IN TXT "upstream txt rr a.a."
+ENTRY_END
+
+; should be NXDOMAIN
+
+STEP 20 QUERY ADDRESS 192.0.0.1
+ENTRY_BEGIN
+REPLY RD
+SECTION QUESTION
+a.a. IN TXT
+ENTRY_END
+
+STEP 21 CHECK_ANSWER
+ENTRY_BEGIN
+MATCH all
+REPLY QR AA RD RA NXDOMAIN
+SECTION QUESTION
+a.a. IN TXT
+SECTION ANSWER
+ENTRY_END
+
+; should be NODATA
+
+STEP 30 QUERY ADDRESS 192.0.1.1
+ENTRY_BEGIN
+REPLY RD
+SECTION QUESTION
+a.a. IN TXT
+ENTRY_END
+
+STEP 31 CHECK_ANSWER
+ENTRY_BEGIN
+MATCH all
+REPLY QR AA RD RA NOERROR
+SECTION QUESTION
+a.a. IN TXT
+SECTION ANSWER
+ENTRY_END
+
+; should be PASSTHRU
+
+STEP 40 QUERY ADDRESS 192.0.3.1
+ENTRY_BEGIN
+REPLY RD
+SECTION QUESTION
+a.a. IN TXT
+ENTRY_END
+
+STEP 41 CHECK_ANSWER
+ENTRY_BEGIN
+MATCH all
+REPLY QR RD RA NOERROR
+SECTION QUESTION
+a.a. IN TXT
+SECTION ANSWER
+a.a. IN TXT "upstream txt rr a.a."
+ENTRY_END
+
+; should be TRUNCATED
+
+STEP 50 QUERY ADDRESS 192.0.4.1
+ENTRY_BEGIN
+REPLY RD
+SECTION QUESTION
+a.a. IN TXT
+ENTRY_END
+
+STEP 51 CHECK_ANSWER
+ENTRY_BEGIN
+MATCH all
+REPLY QR AA TC RD RA NOERROR
+SECTION QUESTION
+a.a. IN TXT
+SECTION ANSWER
+ENTRY_END
+
+; should not be TRUNCATED via TCP
+
+STEP 52 QUERY ADDRESS 192.0.4.1
+ENTRY_BEGIN
+MATCH TCP
+REPLY RD
+SECTION QUESTION
+a.a. IN TXT
+ENTRY_END
+
+STEP 53 CHECK_ANSWER
+ENTRY_BEGIN
+MATCH all TCP
+REPLY QR RD RA NOERROR
+SECTION QUESTION
+a.a. IN TXT
+SECTION ANSWER
+a.a. IN TXT "upstream txt rr a.a."
+ENTRY_END
+
+; should be synthesized
+
+STEP 60 QUERY ADDRESS 192.0.5.1
+ENTRY_BEGIN
+REPLY RD
+SECTION QUESTION
+a.a. IN A
+ENTRY_END
+
+STEP 61 CHECK_ANSWER
+ENTRY_BEGIN
+MATCH all
+REPLY QR AA RD RA NOERROR
+SECTION QUESTION
+a.a. IN A
+SECTION ANSWER
+a.a. IN A 127.0.0.1
+SECTION ADDITIONAL
+rpz.example.com. 3600 IN SOA ns1.rpz.example.com. hostmaster.rpz.example.com. ( 1379078166 28800 7200 604800 7200 )
+ENTRY_END
+
+; should be synthesized
+
+STEP 62 QUERY ADDRESS 192.0.5.1
+ENTRY_BEGIN
+REPLY RD
+SECTION QUESTION
+a.a. IN TXT
+ENTRY_END
+
+STEP 63 CHECK_ANSWER
+ENTRY_BEGIN
+MATCH all
+REPLY QR AA RD RA NOERROR
+SECTION QUESTION
+a.a. IN TXT
+SECTION ANSWER
+a.a. IN TXT "42"
+SECTION ADDITIONAL
+rpz.example.com. 3600 IN SOA ns1.rpz.example.com. hostmaster.rpz.example.com. ( 1379078166 28800 7200 604800 7200 )
+ENTRY_END
+
+; should be synthesized NODATA
+
+STEP 64 QUERY ADDRESS 192.0.5.1
+ENTRY_BEGIN
+REPLY RD
+SECTION QUESTION
+a.a. IN AAAA
+ENTRY_END
+
+STEP 65 CHECK_ANSWER
+ENTRY_BEGIN
+MATCH all
+REPLY QR AA RD RA NOERROR
+SECTION QUESTION
+a.a. IN AAAA
+SECTION ADDITIONAL
+rpz.example.com. 3600 IN SOA ns1.rpz.example.com. hostmaster.rpz.example.com. ( 1379078166 28800 7200 604800 7200 )
+ENTRY_END
+
+; should be DROPPED
+
+STEP 90 QUERY ADDRESS 192.0.2.1
+ENTRY_BEGIN
+REPLY RD
+SECTION QUESTION
+a.a. IN TXT
+ENTRY_END
+
+SCENARIO_END
diff --git a/contrib/unbound/testdata/rpz_nsdname.rpl b/contrib/unbound/testdata/rpz_nsdname.rpl
new file mode 100644
index 000000000000..08ff3c2e2f5b
--- /dev/null
+++ b/contrib/unbound/testdata/rpz_nsdname.rpl
@@ -0,0 +1,390 @@
+; config options
+server:
+ module-config: "respip validator iterator"
+ target-fetch-policy: "0 0 0 0 0"
+ qname-minimisation: no
+ access-control: 192.0.0.0/8 allow
+
+rpz:
+ name: "rpz.example.com."
+ rpz-log: yes
+ rpz-log-name: "rpz.example.com"
+ zonefile:
+TEMPFILE_NAME rpz.example.com
+TEMPFILE_CONTENTS rpz.example.com
+$ORIGIN example.com.
+rpz 3600 IN SOA ns1.rpz.example.com. hostmaster.rpz.example.com. (
+ 1379078166 28800 7200 604800 7200 )
+ 3600 IN NS ns1.rpz.example.com.
+ 3600 IN NS ns2.rpz.example.com.
+$ORIGIN rpz.example.com.
+ns1.gotham.aa.rpz-nsdname CNAME .
+ns1.gotham.bb.rpz-nsdname CNAME *.
+ns1.gotham.cc.rpz-nsdname CNAME rpz-drop.
+ns1.gotham.com.rpz-nsdname CNAME rpz-passthru.
+ns1.gotham.dd.rpz-nsdname CNAME rpz-tcp-only.
+ns1.gotham.ff.rpz-nsdname A 127.0.0.1
+ns1.gotham.ff.rpz-nsdname TXT "42"
+TEMPFILE_END
+
+stub-zone:
+ name: "."
+ stub-addr: 1.1.1.1
+CONFIG_END
+
+SCENARIO_BEGIN Test RPZ nsip triggers
+
+; . --------------------------------------------------------------------------
+RANGE_BEGIN 0 100
+ ADDRESS 1.1.1.1
+ENTRY_BEGIN
+MATCH opcode qtype qname
+ADJUST copy_id
+REPLY QR NOERROR
+SECTION QUESTION
+. IN NS
+SECTION ANSWER
+. IN NS ns.root.
+SECTION ADDITIONAL
+ns.root IN A 1.1.1.1
+ENTRY_END
+
+ENTRY_BEGIN
+MATCH opcode subdomain
+ADJUST copy_id copy_query
+REPLY QR NOERROR
+SECTION QUESTION
+com. IN A
+SECTION AUTHORITY
+com. IN NS ns1.com.
+SECTION ADDITIONAL
+ns1.com. IN A 8.8.8.8
+ENTRY_END
+
+ENTRY_BEGIN
+MATCH opcode subdomain
+ADJUST copy_id copy_query
+REPLY QR NOERROR
+SECTION QUESTION
+aa. IN A
+SECTION AUTHORITY
+aa. IN NS ns1.aa.
+SECTION ADDITIONAL
+ns1.aa. IN A 8.8.0.8
+ENTRY_END
+
+ENTRY_BEGIN
+MATCH opcode subdomain
+ADJUST copy_id copy_query
+REPLY QR NOERROR
+SECTION QUESTION
+bb. IN A
+SECTION AUTHORITY
+bb. IN NS ns1.bb.
+SECTION ADDITIONAL
+ns1.bb. IN A 8.8.1.8
+ENTRY_END
+
+ENTRY_BEGIN
+MATCH opcode subdomain
+ADJUST copy_id copy_query
+REPLY QR NOERROR
+SECTION QUESTION
+cc. IN A
+SECTION AUTHORITY
+cc. IN NS ns1.cc.
+SECTION ADDITIONAL
+ns1.cc. IN A 8.8.2.8
+ENTRY_END
+
+ENTRY_BEGIN
+MATCH opcode subdomain
+ADJUST copy_id copy_query
+REPLY QR NOERROR
+SECTION QUESTION
+dd. IN A
+SECTION AUTHORITY
+dd. IN NS ns1.dd.
+SECTION ADDITIONAL
+ns1.dd. IN A 8.8.3.8
+ENTRY_END
+
+ENTRY_BEGIN
+MATCH opcode subdomain
+ADJUST copy_id copy_query
+REPLY QR NOERROR
+SECTION QUESTION
+ee. IN A
+SECTION AUTHORITY
+ee. IN NS ns1.ee.
+SECTION ADDITIONAL
+ns1.ee. IN A 8.8.5.8
+ENTRY_END
+
+ENTRY_BEGIN
+MATCH opcode subdomain
+ADJUST copy_id copy_query
+REPLY QR NOERROR
+SECTION QUESTION
+ff. IN A
+SECTION AUTHORITY
+ff. IN NS ns1.ff.
+SECTION ADDITIONAL
+ns1.ff. IN A 8.8.6.8
+ENTRY_END
+
+RANGE_END
+
+; com. -----------------------------------------------------------------------
+RANGE_BEGIN 0 100
+ ADDRESS 8.8.8.8
+
+ENTRY_BEGIN
+MATCH opcode qtype qname
+ADJUST copy_id
+REPLY QR NOERROR
+SECTION QUESTION
+com. IN NS
+SECTION ANSWER
+com. IN NS ns1.com.
+SECTION ADDITIONAL
+ns1.com. IN A 8.8.8.8
+ENTRY_END
+
+ENTRY_BEGIN
+MATCH opcode subdomain
+ADJUST copy_id copy_query
+REPLY QR NOERROR
+SECTION QUESTION
+gotham.com. IN A
+SECTION AUTHORITY
+gotham.com. IN NS ns1.gotham.com.
+SECTION ADDITIONAL
+ns1.gotham.com. IN A 192.0.6.1
+ENTRY_END
+
+RANGE_END
+
+; aa. ------------------------------------------------------------------------
+RANGE_BEGIN 0 100
+ ADDRESS 8.8.0.8
+
+ENTRY_BEGIN
+MATCH opcode qtype qname
+ADJUST copy_id
+REPLY QR NOERROR
+SECTION QUESTION
+aa. IN NS
+SECTION ANSWER
+aa. IN NS ns1.aa.
+SECTION ADDITIONAL
+ns1.aa. IN A 8.8.0.8
+ENTRY_END
+
+ENTRY_BEGIN
+MATCH opcode subdomain
+ADJUST copy_id copy_query
+REPLY QR NOERROR
+SECTION QUESTION
+gotham.aa. IN A
+SECTION AUTHORITY
+gotham.aa. IN NS ns1.gotham.aa.
+SECTION ADDITIONAL
+ns1.gotham.aa. IN A 192.0.0.1
+ENTRY_END
+
+RANGE_END
+
+; bb. ------------------------------------------------------------------------
+RANGE_BEGIN 0 100
+ ADDRESS 8.8.1.8
+
+ENTRY_BEGIN
+MATCH opcode qtype qname
+ADJUST copy_id
+REPLY QR NOERROR
+SECTION QUESTION
+bb. IN NS
+SECTION ANSWER
+bb. IN NS ns1.bb.
+SECTION ADDITIONAL
+ns1.bb. IN A 8.8.1.8
+ENTRY_END
+
+ENTRY_BEGIN
+MATCH opcode subdomain
+ADJUST copy_id copy_query
+REPLY QR NOERROR
+SECTION QUESTION
+gotham.bb. IN A
+SECTION AUTHORITY
+gotham.bb. IN NS ns1.gotham.bb.
+SECTION ADDITIONAL
+ns1.gotham.bb. IN A 192.0.1.1
+ENTRY_END
+
+RANGE_END
+
+; ff. ------------------------------------------------------------------------
+RANGE_BEGIN 0 100
+ ADDRESS 8.8.6.8
+
+ENTRY_BEGIN
+MATCH opcode qtype qname
+ADJUST copy_id
+REPLY QR NOERROR
+SECTION QUESTION
+ff. IN NS
+SECTION ANSWER
+ff. IN NS ns1.ff.
+SECTION ADDITIONAL
+ns1.ff. IN A 8.8.6.8
+ENTRY_END
+
+ENTRY_BEGIN
+MATCH opcode subdomain
+ADJUST copy_id copy_query
+REPLY QR NOERROR
+SECTION QUESTION
+gotham.ff. IN A
+SECTION AUTHORITY
+gotham.ff. IN NS ns1.gotham.ff.
+SECTION ADDITIONAL
+ns1.gotham.ff. IN A 192.0.5.1
+ENTRY_END
+
+RANGE_END
+
+; ns1.gotham.com. ------------------------------------------------------------
+RANGE_BEGIN 0 100
+ ADDRESS 192.0.6.1
+
+ENTRY_BEGIN
+MATCH opcode qtype qname
+ADJUST copy_id
+REPLY QR NOERROR
+SECTION QUESTION
+gotham.com. IN A
+SECTION ANSWER
+gotham.com. IN A 192.0.6.2
+ENTRY_END
+
+RANGE_END
+
+; ns1.gotham.aa. -------------------------------------------------------------
+RANGE_BEGIN 0 100
+ ADDRESS 192.0.0.1
+
+ENTRY_BEGIN
+MATCH opcode qtype qname
+ADJUST copy_id
+REPLY QR NOERROR
+SECTION QUESTION
+gotham.aa. IN A
+SECTION ANSWER
+gotham.aa. IN A 192.0.0.2
+ENTRY_END
+
+RANGE_END
+
+; ns1.gotham.bb. -------------------------------------------------------------
+RANGE_BEGIN 0 100
+ ADDRESS 192.0.1.1
+
+ENTRY_BEGIN
+MATCH opcode qtype qname
+ADJUST copy_id
+REPLY QR NOERROR
+SECTION QUESTION
+gotham.bb. IN A
+SECTION ANSWER
+gotham.bb. IN A 192.0.1.2
+ENTRY_END
+
+RANGE_END
+
+; ns1.gotham.ff. -------------------------------------------------------------
+RANGE_BEGIN 0 100
+ ADDRESS 192.0.5.1
+
+ENTRY_BEGIN
+MATCH opcode qtype qname
+ADJUST copy_id
+REPLY QR NOERROR
+SECTION QUESTION
+gotham.ff. IN A
+SECTION ANSWER
+gotham.ff. IN A 192.0.5.2
+ENTRY_END
+
+RANGE_END
+
+; ----------------------------------------------------------------------------
+
+STEP 1 QUERY
+ENTRY_BEGIN
+REPLY RD
+SECTION QUESTION
+gotham.com. IN A
+ENTRY_END
+
+STEP 2 CHECK_ANSWER
+ENTRY_BEGIN
+MATCH all
+REPLY QR RD RA NOERROR
+SECTION QUESTION
+gotham.com. IN A
+SECTION ANSWER
+gotham.com. IN A 192.0.6.2
+ENTRY_END
+
+STEP 10 QUERY
+ENTRY_BEGIN
+REPLY RD
+SECTION QUESTION
+gotham.aa. IN A
+ENTRY_END
+
+STEP 11 CHECK_ANSWER
+ENTRY_BEGIN
+MATCH all
+REPLY QR RD RA NXDOMAIN
+SECTION QUESTION
+gotham.aa. IN A
+SECTION ANSWER
+ENTRY_END
+
+STEP 20 QUERY
+ENTRY_BEGIN
+REPLY RD
+SECTION QUESTION
+gotham.bb. IN A
+ENTRY_END
+
+STEP 21 CHECK_ANSWER
+ENTRY_BEGIN
+MATCH all
+REPLY QR RD RA AA NOERROR
+SECTION QUESTION
+gotham.bb. IN A
+SECTION ANSWER
+ENTRY_END
+
+STEP 30 QUERY
+ENTRY_BEGIN
+REPLY RD
+SECTION QUESTION
+gotham.ff. IN A
+ENTRY_END
+
+STEP 31 CHECK_ANSWER
+ENTRY_BEGIN
+MATCH all
+REPLY QR RD RA AA NOERROR
+SECTION QUESTION
+gotham.ff. IN A
+SECTION ANSWER
+gotham.ff. IN A 127.0.0.1
+ENTRY_END
+
+SCENARIO_END
diff --git a/contrib/unbound/testdata/rpz_nsip.rpl b/contrib/unbound/testdata/rpz_nsip.rpl
new file mode 100644
index 000000000000..ac132cae0996
--- /dev/null
+++ b/contrib/unbound/testdata/rpz_nsip.rpl
@@ -0,0 +1,408 @@
+; config options
+server:
+ module-config: "respip validator iterator"
+ target-fetch-policy: "0 0 0 0 0"
+ qname-minimisation: no
+ access-control: 192.0.0.0/8 allow
+
+rpz:
+ name: "rpz.example.com."
+ rpz-log: yes
+ rpz-log-name: "rpz.example.com"
+ zonefile:
+TEMPFILE_NAME rpz.example.com
+TEMPFILE_CONTENTS rpz.example.com
+$ORIGIN example.com.
+rpz 3600 IN SOA ns1.rpz.gotham.com. hostmaster.rpz.example.com. (
+ 1379078166 28800 7200 604800 7200 )
+ 3600 IN NS ns1.rpz.example.com.
+ 3600 IN NS ns2.rpz.example.com.
+$ORIGIN rpz.example.com.
+24.0.0.0.192.rpz-nsip CNAME .
+24.0.1.0.192.rpz-nsip CNAME *.
+24.0.2.0.192.rpz-nsip CNAME rpz-drop.
+24.0.3.0.192.rpz-nsip CNAME rpz-passthru.
+24.0.4.0.192.rpz-nsip CNAME rpz-tcp-only.
+24.0.5.0.192.rpz-nsip A 127.0.0.1
+24.0.5.0.192.rpz-nsip TXT "42"
+TEMPFILE_END
+
+stub-zone:
+ name: "."
+ stub-addr: 1.1.1.1
+CONFIG_END
+
+SCENARIO_BEGIN Test RPZ nsip triggers
+
+; . --------------------------------------------------------------------------
+RANGE_BEGIN 0 100
+ ADDRESS 1.1.1.1
+ENTRY_BEGIN
+MATCH opcode qtype qname
+ADJUST copy_id
+REPLY QR NOERROR
+SECTION QUESTION
+. IN NS
+SECTION ANSWER
+. IN NS ns.root.
+SECTION ADDITIONAL
+ns.root IN A 1.1.1.1
+ENTRY_END
+
+ENTRY_BEGIN
+MATCH opcode subdomain
+ADJUST copy_id copy_query
+REPLY QR NOERROR
+SECTION QUESTION
+com. IN A
+SECTION AUTHORITY
+com. IN NS ns1.com.
+SECTION ADDITIONAL
+ns1.com. IN A 8.8.8.8
+ENTRY_END
+
+ENTRY_BEGIN
+MATCH opcode subdomain
+ADJUST copy_id copy_query
+REPLY QR NOERROR
+SECTION QUESTION
+aa. IN A
+SECTION AUTHORITY
+aa. IN NS ns1.aa.
+SECTION ADDITIONAL
+ns1.aa. IN A 8.8.0.8
+ENTRY_END
+
+ENTRY_BEGIN
+MATCH opcode subdomain
+ADJUST copy_id copy_query
+REPLY QR NOERROR
+SECTION QUESTION
+bb. IN A
+SECTION AUTHORITY
+bb. IN NS ns1.bb.
+SECTION ADDITIONAL
+ns1.bb. IN A 8.8.1.8
+ENTRY_END
+
+ENTRY_BEGIN
+MATCH opcode subdomain
+ADJUST copy_id copy_query
+REPLY QR NOERROR
+SECTION QUESTION
+cc. IN A
+SECTION AUTHORITY
+cc. IN NS ns1.cc.
+SECTION ADDITIONAL
+ns1.cc. IN A 8.8.2.8
+ENTRY_END
+
+ENTRY_BEGIN
+MATCH opcode subdomain
+ADJUST copy_id copy_query
+REPLY QR NOERROR
+SECTION QUESTION
+dd. IN A
+SECTION AUTHORITY
+dd. IN NS ns1.dd.
+SECTION ADDITIONAL
+ns1.dd. IN A 8.8.3.8
+ENTRY_END
+
+ENTRY_BEGIN
+MATCH opcode subdomain
+ADJUST copy_id copy_query
+REPLY QR NOERROR
+SECTION QUESTION
+ee. IN A
+SECTION AUTHORITY
+ee. IN NS ns1.ee.
+SECTION ADDITIONAL
+ns1.ee. IN A 8.8.5.8
+ENTRY_END
+
+ENTRY_BEGIN
+MATCH opcode subdomain
+ADJUST copy_id copy_query
+REPLY QR NOERROR
+SECTION QUESTION
+ff. IN A
+SECTION AUTHORITY
+ff. IN NS ns1.ff.
+SECTION ADDITIONAL
+ns1.ff. IN A 8.8.6.8
+ENTRY_END
+
+RANGE_END
+
+; com. -----------------------------------------------------------------------
+RANGE_BEGIN 0 100
+ ADDRESS 8.8.8.8
+
+ENTRY_BEGIN
+MATCH opcode qtype qname
+ADJUST copy_id
+REPLY QR NOERROR
+SECTION QUESTION
+com. IN NS
+SECTION ANSWER
+com. IN NS ns1.com.
+SECTION ADDITIONAL
+ns1.com. IN A 8.8.8.8
+ENTRY_END
+
+ENTRY_BEGIN
+MATCH opcode subdomain
+ADJUST copy_id copy_query
+REPLY QR NOERROR
+SECTION QUESTION
+gotham.com. IN A
+SECTION AUTHORITY
+gotham.com. IN NS ns1.gotham.com.
+SECTION ADDITIONAL
+ns1.gotham.com. IN A 192.0.6.1
+ENTRY_END
+
+RANGE_END
+
+; aa. ------------------------------------------------------------------------
+RANGE_BEGIN 0 100
+ ADDRESS 8.8.0.8
+
+ENTRY_BEGIN
+MATCH opcode qtype qname
+ADJUST copy_id
+REPLY QR NOERROR
+SECTION QUESTION
+aa. IN NS
+SECTION ANSWER
+aa. IN NS ns1.aa.
+SECTION ADDITIONAL
+ns1.aa. IN A 8.8.0.8
+ENTRY_END
+
+ENTRY_BEGIN
+MATCH opcode subdomain
+ADJUST copy_id copy_query
+REPLY QR NOERROR
+SECTION QUESTION
+gotham.aa. IN A
+SECTION AUTHORITY
+gotham.aa. IN NS ns1.gotham.aa.
+SECTION ADDITIONAL
+ns1.gotham.aa. IN A 192.0.0.1
+ENTRY_END
+
+RANGE_END
+
+; bb. ------------------------------------------------------------------------
+RANGE_BEGIN 0 100
+ ADDRESS 8.8.1.8
+
+ENTRY_BEGIN
+MATCH opcode qtype qname
+ADJUST copy_id
+REPLY QR NOERROR
+SECTION QUESTION
+bb. IN NS
+SECTION ANSWER
+bb. IN NS ns1.bb.
+SECTION ADDITIONAL
+ns1.bb. IN A 8.8.1.8
+ENTRY_END
+
+ENTRY_BEGIN
+MATCH opcode subdomain
+ADJUST copy_id copy_query
+REPLY QR NOERROR
+SECTION QUESTION
+gotham.bb. IN A
+SECTION AUTHORITY
+gotham.bb. IN NS ns1.gotham.bb.
+SECTION ADDITIONAL
+ns1.gotham.bb. IN A 192.0.1.1
+ENTRY_END
+
+RANGE_END
+
+; ff. ------------------------------------------------------------------------
+RANGE_BEGIN 0 100
+ ADDRESS 8.8.6.8
+
+ENTRY_BEGIN
+MATCH opcode qtype qname
+ADJUST copy_id
+REPLY QR NOERROR
+SECTION QUESTION
+ff. IN NS
+SECTION ANSWER
+ff. IN NS ns1.ff.
+SECTION ADDITIONAL
+ns1.ff. IN A 8.8.6.8
+ENTRY_END
+
+ENTRY_BEGIN
+MATCH opcode subdomain
+ADJUST copy_id copy_query
+REPLY QR NOERROR
+SECTION QUESTION
+gotham.ff. IN A
+SECTION AUTHORITY
+gotham.ff. IN NS ns1.gotham.ff.
+SECTION ADDITIONAL
+ns1.gotham.ff. IN A 192.0.5.1
+ENTRY_END
+
+RANGE_END
+
+; ns1.gotham.com. ------------------------------------------------------------
+RANGE_BEGIN 0 100
+ ADDRESS 192.0.6.1
+
+ENTRY_BEGIN
+MATCH opcode qtype qname
+ADJUST copy_id
+REPLY QR NOERROR
+SECTION QUESTION
+gotham.com. IN A
+SECTION ANSWER
+gotham.com. IN A 192.0.6.2
+ENTRY_END
+
+RANGE_END
+
+; ns1.gotham.aa. -------------------------------------------------------------
+RANGE_BEGIN 0 100
+ ADDRESS 192.0.0.1
+
+ENTRY_BEGIN
+MATCH opcode qtype qname
+ADJUST copy_id
+REPLY QR NOERROR
+SECTION QUESTION
+gotham.aa. IN A
+SECTION ANSWER
+gotham.aa. IN A 192.0.0.2
+ENTRY_END
+
+RANGE_END
+
+; ns1.gotham.bb. -------------------------------------------------------------
+RANGE_BEGIN 0 100
+ ADDRESS 192.0.1.1
+
+ENTRY_BEGIN
+MATCH opcode qtype qname
+ADJUST copy_id
+REPLY QR NOERROR
+SECTION QUESTION
+gotham.bb. IN A
+SECTION ANSWER
+gotham.bb. IN A 192.0.1.2
+ENTRY_END
+
+RANGE_END
+
+; ns1.gotham.ff. -------------------------------------------------------------
+RANGE_BEGIN 0 100
+ ADDRESS 192.0.5.1
+
+ENTRY_BEGIN
+MATCH opcode qtype qname
+ADJUST copy_id
+REPLY QR NOERROR
+SECTION QUESTION
+gotham.ff. IN A
+SECTION ANSWER
+gotham.ff. IN A 192.0.5.2
+ENTRY_END
+
+RANGE_END
+
+; ----------------------------------------------------------------------------
+
+STEP 1 QUERY
+ENTRY_BEGIN
+REPLY RD
+SECTION QUESTION
+gotham.com. IN A
+ENTRY_END
+
+STEP 2 CHECK_ANSWER
+ENTRY_BEGIN
+MATCH all
+REPLY QR RD RA NOERROR
+SECTION QUESTION
+gotham.com. IN A
+SECTION ANSWER
+gotham.com. IN A 192.0.6.2
+ENTRY_END
+
+STEP 10 QUERY
+ENTRY_BEGIN
+REPLY RD
+SECTION QUESTION
+gotham.aa. IN A
+ENTRY_END
+
+STEP 11 CHECK_ANSWER
+ENTRY_BEGIN
+MATCH all
+REPLY QR RD RA NXDOMAIN
+SECTION QUESTION
+gotham.aa. IN A
+SECTION ANSWER
+ENTRY_END
+
+STEP 20 QUERY
+ENTRY_BEGIN
+REPLY RD
+SECTION QUESTION
+gotham.bb. IN A
+ENTRY_END
+
+STEP 21 CHECK_ANSWER
+ENTRY_BEGIN
+MATCH all
+REPLY QR RD RA AA NOERROR
+SECTION QUESTION
+gotham.bb. IN A
+SECTION ANSWER
+ENTRY_END
+
+STEP 30 QUERY
+ENTRY_BEGIN
+REPLY RD
+SECTION QUESTION
+gotham.ff. IN A
+ENTRY_END
+
+STEP 31 CHECK_ANSWER
+ENTRY_BEGIN
+MATCH all
+REPLY QR RD RA AA NOERROR
+SECTION QUESTION
+gotham.ff. IN A
+SECTION ANSWER
+gotham.ff. IN A 127.0.0.1
+ENTRY_END
+
+; again with more cache items
+STEP 40 QUERY
+ENTRY_BEGIN
+REPLY RD
+SECTION QUESTION
+gotham.ff. IN A
+ENTRY_END
+
+STEP 41 CHECK_ANSWER
+ENTRY_BEGIN
+MATCH all
+REPLY QR RD RA AA NOERROR
+SECTION QUESTION
+gotham.ff. IN A
+SECTION ANSWER
+gotham.ff. IN A 127.0.0.1
+ENTRY_END
+
+SCENARIO_END
diff --git a/contrib/unbound/testdata/rpz_qname_tcponly.rpl b/contrib/unbound/testdata/rpz_qname_tcponly.rpl
new file mode 100644
index 000000000000..d30b88616227
--- /dev/null
+++ b/contrib/unbound/testdata/rpz_qname_tcponly.rpl
@@ -0,0 +1,117 @@
+; config options
+server:
+ module-config: "respip validator iterator"
+ target-fetch-policy: "0 0 0 0 0"
+ qname-minimisation: no
+
+rpz:
+ name: "rpz.example.com."
+ zonefile:
+TEMPFILE_NAME rpz.example.com
+TEMPFILE_CONTENTS rpz.example.com
+$ORIGIN example.com.
+rpz 3600 IN SOA ns1.rpz.example.com. hostmaster.rpz.example.com. (
+ 1379078166 28800 7200 604800 7200 )
+ 3600 IN NS ns1.rpz.example.com.
+ 3600 IN NS ns2.rpz.example.com.
+$ORIGIN rpz.example.com.
+a.a CNAME rpz-passthru.
+b.a CNAME rpz-tcp-only.
+TEMPFILE_END
+
+stub-zone:
+ name: "a."
+ stub-addr: 10.20.30.40
+CONFIG_END
+
+SCENARIO_BEGIN Test RPZ qname trigger and tcp-only action
+
+RANGE_BEGIN 0 100
+ ADDRESS 10.20.30.40
+ENTRY_BEGIN
+MATCH opcode qtype qname
+ADJUST copy_id
+REPLY QR NOERROR
+SECTION QUESTION
+a. IN NS
+SECTION ANSWER
+a. IN NS ns.a.
+SECTION ADDITIONAL
+ns.a IN A 10.20.30.40
+ENTRY_END
+
+ENTRY_BEGIN
+MATCH opcode qtype qname
+ADJUST copy_id
+REPLY QR NOERROR
+SECTION QUESTION
+a.a. IN TXT
+SECTION ANSWER
+a.a. IN TXT "upstream txt rr a.a."
+ENTRY_END
+
+ENTRY_BEGIN
+MATCH opcode qtype qname
+ADJUST copy_id
+REPLY QR NOERROR
+SECTION QUESTION
+b.a. IN TXT
+SECTION ANSWER
+b.a. IN TXT "upstream txt rr b.a."
+ENTRY_END
+
+RANGE_END
+
+STEP 10 QUERY
+ENTRY_BEGIN
+REPLY RD
+SECTION QUESTION
+a.a. IN TXT
+ENTRY_END
+
+STEP 11 CHECK_ANSWER
+ENTRY_BEGIN
+MATCH all
+REPLY QR RD RA NOERROR
+SECTION QUESTION
+a.a. IN TXT
+SECTION ANSWER
+a.a. IN TXT "upstream txt rr a.a."
+ENTRY_END
+
+STEP 20 QUERY
+ENTRY_BEGIN
+MATCH UDP
+REPLY RD
+SECTION QUESTION
+b.a. IN TXT
+ENTRY_END
+
+STEP 21 CHECK_ANSWER
+ENTRY_BEGIN
+MATCH all UDP
+REPLY QR AA TC RD RA NOERROR
+SECTION QUESTION
+b.a. IN TXT
+SECTION ANSWER
+ENTRY_END
+
+STEP 30 QUERY
+ENTRY_BEGIN
+MATCH TCP
+REPLY RD
+SECTION QUESTION
+b.a. IN TXT
+ENTRY_END
+
+STEP 31 CHECK_ANSWER
+ENTRY_BEGIN
+MATCH all TCP
+REPLY QR RD RA NOERROR
+SECTION QUESTION
+b.a. IN TXT
+SECTION ANSWER
+b.a. IN TXT "upstream txt rr b.a."
+ENTRY_END
+
+SCENARIO_END
diff --git a/contrib/unbound/testdata/rpz_respip_tcponly.rpl b/contrib/unbound/testdata/rpz_respip_tcponly.rpl
new file mode 100644
index 000000000000..c495de2038a1
--- /dev/null
+++ b/contrib/unbound/testdata/rpz_respip_tcponly.rpl
@@ -0,0 +1,207 @@
+; config options
+server:
+ module-config: "respip validator iterator"
+ target-fetch-policy: "0 0 0 0 0"
+ qname-minimisation: no
+
+rpz:
+ name: "rpz.example.com."
+ zonefile:
+TEMPFILE_NAME rpz.example.com
+TEMPFILE_CONTENTS rpz.example.com
+$ORIGIN example.com.
+rpz 3600 IN SOA ns1.rpz.example.com. hostmaster.rpz.example.com. (
+ 1379078166 28800 7200 604800 7200 )
+ 3600 IN NS ns1.rpz.example.com.
+ 3600 IN NS ns2.rpz.example.com.
+$ORIGIN rpz.example.com.
+8.0.0.0.10.rpz-ip CNAME *.
+16.0.0.10.10.rpz-ip CNAME .
+24.0.10.10.10.rpz-ip CNAME rpz-drop.
+32.10.10.10.10.rpz-ip CNAME rpz-passthru.
+32.1.1.1.10.rpz-ip CNAME rpz-tcp-only.
+TEMPFILE_END
+
+stub-zone:
+ name: "."
+ stub-addr: 10.20.30.40
+CONFIG_END
+
+SCENARIO_BEGIN Test RPZ response IP address trigger and tcp-only action
+
+RANGE_BEGIN 0 100
+ ADDRESS 10.20.30.40
+ENTRY_BEGIN
+MATCH opcode qtype qname
+ADJUST copy_id
+REPLY QR NOERROR
+SECTION QUESTION
+. IN NS
+SECTION ANSWER
+. IN NS ns.
+SECTION ADDITIONAL
+ns. IN A 10.20.30.40
+ENTRY_END
+
+ENTRY_BEGIN
+MATCH opcode qtype qname
+ADJUST copy_id
+REPLY QR NOERROR
+SECTION QUESTION
+a. IN A
+SECTION ANSWER
+a. IN A 10.0.0.123
+ENTRY_END
+
+ENTRY_BEGIN
+MATCH opcode qtype qname
+ADJUST copy_id
+REPLY QR NOERROR
+SECTION QUESTION
+b. IN A
+SECTION ANSWER
+b. IN A 10.1.0.123
+ENTRY_END
+
+ENTRY_BEGIN
+MATCH opcode qtype qname
+ADJUST copy_id
+REPLY QR NOERROR
+SECTION QUESTION
+c. IN A
+SECTION ANSWER
+c. IN A 10.11.0.123
+ENTRY_END
+
+ENTRY_BEGIN
+MATCH opcode qtype qname
+ADJUST copy_id
+REPLY QR NOERROR
+SECTION QUESTION
+d. IN A
+SECTION ANSWER
+d. IN A 10.10.0.123
+ENTRY_END
+
+ENTRY_BEGIN
+MATCH opcode qtype qname
+ADJUST copy_id
+REPLY QR NOERROR
+SECTION QUESTION
+f. IN A
+SECTION ANSWER
+f. IN A 10.10.10.10
+ENTRY_END
+
+ENTRY_BEGIN
+MATCH opcode qtype qname
+ADJUST copy_id
+REPLY QR NOERROR
+SECTION QUESTION
+y. IN A
+SECTION ANSWER
+y. IN A 10.1.1.1
+ENTRY_END
+
+RANGE_END
+
+STEP 1 QUERY
+ENTRY_BEGIN
+REPLY RD
+SECTION QUESTION
+a. IN A
+ENTRY_END
+
+STEP 2 CHECK_ANSWER
+ENTRY_BEGIN
+MATCH all
+REPLY QR RD RA NOERROR
+SECTION QUESTION
+a. IN A
+SECTION ANSWER
+ENTRY_END
+
+STEP 10 QUERY
+ENTRY_BEGIN
+REPLY RD
+SECTION QUESTION
+b. IN A
+ENTRY_END
+
+STEP 11 CHECK_ANSWER
+ENTRY_BEGIN
+MATCH all
+REPLY QR RD RA NOERROR
+SECTION QUESTION
+b. IN A
+SECTION ANSWER
+ENTRY_END
+
+STEP 13 QUERY
+ENTRY_BEGIN
+REPLY RD
+SECTION QUESTION
+d. IN A
+ENTRY_END
+
+STEP 14 CHECK_ANSWER
+ENTRY_BEGIN
+MATCH all
+REPLY QR RD RA NXDOMAIN
+SECTION QUESTION
+d. IN A
+SECTION ANSWER
+ENTRY_END
+
+STEP 17 QUERY
+ENTRY_BEGIN
+REPLY RD
+SECTION QUESTION
+f. IN A
+ENTRY_END
+
+STEP 18 CHECK_ANSWER
+ENTRY_BEGIN
+MATCH all
+REPLY QR RD RA NOERROR
+SECTION QUESTION
+f. IN A
+SECTION ANSWER
+f. IN A 10.10.10.10
+ENTRY_END
+
+STEP 30 QUERY
+ENTRY_BEGIN
+REPLY RD
+SECTION QUESTION
+y. IN A
+ENTRY_END
+
+STEP 31 CHECK_ANSWER
+ENTRY_BEGIN
+MATCH all
+REPLY QR TC RD RA NOERROR
+SECTION QUESTION
+y. IN A
+SECTION ANSWER
+ENTRY_END
+
+STEP 40 QUERY
+ENTRY_BEGIN
+MATCH TCP
+REPLY RD
+SECTION QUESTION
+y. IN A
+ENTRY_END
+
+STEP 41 CHECK_ANSWER
+ENTRY_BEGIN
+MATCH all TCP
+REPLY QR RD RA NOERROR
+SECTION QUESTION
+y. IN A
+SECTION ANSWER
+y. IN A 10.1.1.1
+ENTRY_END
+
+SCENARIO_END
diff --git a/contrib/unbound/testdata/stub_udp_with_tcp_upstream.tdir/stub_udp_with_tcp_upstream.conf b/contrib/unbound/testdata/stub_udp_with_tcp_upstream.tdir/stub_udp_with_tcp_upstream.conf
new file mode 100644
index 000000000000..d57c787b154c
--- /dev/null
+++ b/contrib/unbound/testdata/stub_udp_with_tcp_upstream.tdir/stub_udp_with_tcp_upstream.conf
@@ -0,0 +1,19 @@
+server:
+ verbosity: 2
+ # num-threads: 1
+ interface: 127.0.0.1
+ port: @PORT@
+ use-syslog: no
+ directory: ""
+ pidfile: "unbound.pid"
+ chroot: ""
+ username: ""
+ do-not-query-localhost: no
+stub-zone:
+ name: "tcp.example.com"
+ stub-addr: "127.0.0.1@@TOPORT@"
+ stub-tcp-upstream: "yes"
+stub-zone:
+ name: "udp.example.com"
+ stub-addr: "127.0.0.1@@TOPORT@"
+ stub-tcp-upstream: "no" \ No newline at end of file
diff --git a/contrib/unbound/testdata/stub_udp_with_tcp_upstream.tdir/stub_udp_with_tcp_upstream.dsc b/contrib/unbound/testdata/stub_udp_with_tcp_upstream.tdir/stub_udp_with_tcp_upstream.dsc
new file mode 100644
index 000000000000..526ff67f98f9
--- /dev/null
+++ b/contrib/unbound/testdata/stub_udp_with_tcp_upstream.tdir/stub_udp_with_tcp_upstream.dsc
@@ -0,0 +1,16 @@
+BaseName: stub_udp_with_tcp_upstream
+Version: 1.0
+Description: Stub server contacted via UDP with tcp upstream.
+CreationDate: Thu Aug 5 07:44:41 CEST 2021
+Maintainer: ziollek
+Category:
+Component:
+CmdDepends:
+Depends:
+Help:
+Pre: stub_udp_with_tcp_upstream.pre
+Post: stub_udp_with_tcp_upstream.post
+Test: stub_udp_with_tcp_upstream.test
+AuxFiles:
+Passed:
+Failure:
diff --git a/contrib/unbound/testdata/stub_udp_with_tcp_upstream.tdir/stub_udp_with_tcp_upstream.post b/contrib/unbound/testdata/stub_udp_with_tcp_upstream.tdir/stub_udp_with_tcp_upstream.post
new file mode 100644
index 000000000000..c804b6c46d64
--- /dev/null
+++ b/contrib/unbound/testdata/stub_udp_with_tcp_upstream.tdir/stub_udp_with_tcp_upstream.post
@@ -0,0 +1,10 @@
+# #-- stub_udp_with_tcp_upstream.post --#
+# source the master var file when it's there
+[ -f ../.tpkg.var.master ] && source ../.tpkg.var.master
+# source the test var file when it's there
+[ -f .tpkg.var.test ] && source .tpkg.var.test
+#
+# do your teardown here
+. ../common.sh
+kill_pid $FWD_PID
+kill_pid $UNBOUND_PID
diff --git a/contrib/unbound/testdata/stub_udp_with_tcp_upstream.tdir/stub_udp_with_tcp_upstream.pre b/contrib/unbound/testdata/stub_udp_with_tcp_upstream.tdir/stub_udp_with_tcp_upstream.pre
new file mode 100644
index 000000000000..2bca63b9d56b
--- /dev/null
+++ b/contrib/unbound/testdata/stub_udp_with_tcp_upstream.tdir/stub_udp_with_tcp_upstream.pre
@@ -0,0 +1,35 @@
+# #-- stub_udp_with_tcp_upstream.pre--#
+# source the master var file when it's there
+[ -f ../.tpkg.var.master ] && source ../.tpkg.var.master
+# use .tpkg.var.test for in test variable passing
+[ -f .tpkg.var.test ] && source .tpkg.var.test
+. ../common.sh
+
+get_random_port 2
+UNBOUND_PORT=$RND_PORT
+FWD_PORT=$(($RND_PORT + 1))
+echo "UNBOUND_PORT=$UNBOUND_PORT" >> .tpkg.var.test
+echo "FWD_PORT=$FWD_PORT" >> .tpkg.var.test
+
+# start forwarder
+get_ldns_testns
+$LDNS_TESTNS -p $FWD_PORT stub_udp_with_tcp_upstream.testns >fwd.log 2>&1 &
+FWD_PID=$!
+echo "FWD_PID=$FWD_PID" >> .tpkg.var.test
+
+# make config file
+sed -e 's/@PORT\@/'$UNBOUND_PORT'/' -e 's/@TOPORT\@/'$FWD_PORT'/' < stub_udp_with_tcp_upstream.conf > ub.conf
+# start unbound in the background
+PRE="../.."
+$PRE/unbound -d -c ub.conf >unbound.log 2>&1 &
+UNBOUND_PID=$!
+echo "UNBOUND_PID=$UNBOUND_PID" >> .tpkg.var.test
+
+cat .tpkg.var.test
+
+# wait for forwarder to come up
+wait_ldns_testns_up fwd.log
+
+# wait for unbound to come up
+wait_unbound_up unbound.log
+
diff --git a/contrib/unbound/testdata/stub_udp_with_tcp_upstream.tdir/stub_udp_with_tcp_upstream.test b/contrib/unbound/testdata/stub_udp_with_tcp_upstream.tdir/stub_udp_with_tcp_upstream.test
new file mode 100644
index 000000000000..43591ac16c0f
--- /dev/null
+++ b/contrib/unbound/testdata/stub_udp_with_tcp_upstream.tdir/stub_udp_with_tcp_upstream.test
@@ -0,0 +1,37 @@
+# #-- stub_udp_with_tcp_upstream.test --#
+# source the master var file when it's there
+[ -f ../.tpkg.var.master ] && source ../.tpkg.var.master
+# use .tpkg.var.test for in test variable passing
+[ -f .tpkg.var.test ] && source .tpkg.var.test
+
+PRE="../.."
+# do the test
+echo "> dig tcp.example.com."
+dig @127.0.0.1 -p $UNBOUND_PORT tcp.example.com. | tee outfile
+echo "> cat logfiles"
+cat fwd.log
+cat unbound.log
+echo "> check answer"
+if grep "10.20.30.40" outfile; then
+ echo "OK"
+else
+ echo "Not OK"
+ exit 1
+fi
+
+
+# check if second stub is requested via udp
+echo "> dig udp.example.com."
+dig @127.0.0.1 -p $UNBOUND_PORT udp.example.com. | tee outfile
+echo "> cat logfiles"
+cat fwd.log
+cat unbound.log
+echo "> check answer"
+if grep "10.20.30.80" outfile; then
+ echo "OK"
+else
+ echo "Not OK"
+ exit 1
+fi
+
+exit 0
diff --git a/contrib/unbound/testdata/stub_udp_with_tcp_upstream.tdir/stub_udp_with_tcp_upstream.testns b/contrib/unbound/testdata/stub_udp_with_tcp_upstream.tdir/stub_udp_with_tcp_upstream.testns
new file mode 100644
index 000000000000..f2155414e045
--- /dev/null
+++ b/contrib/unbound/testdata/stub_udp_with_tcp_upstream.tdir/stub_udp_with_tcp_upstream.testns
@@ -0,0 +1,48 @@
+; nameserver test file
+$ORIGIN example.com.
+$TTL 3600
+
+ENTRY_BEGIN
+MATCH opcode qtype qname
+MATCH TCP
+REPLY QR AA NOERROR
+ADJUST copy_id
+SECTION QUESTION
+tcp IN A
+SECTION ANSWER
+tcp IN A 10.20.30.40
+SECTION AUTHORITY
+@ IN NS ns.example.com.
+SECTION ADDITIONAL
+ns IN A 127.0.0.1
+ENTRY_END
+
+ENTRY_BEGIN
+MATCH opcode qtype qname
+MATCH UDP
+REPLY QR AA NOERROR
+ADJUST copy_id
+SECTION QUESTION
+udp IN A
+SECTION ANSWER
+udp IN A 10.20.30.80
+SECTION AUTHORITY
+@ IN NS ns.example.com.
+SECTION ADDITIONAL
+ns IN A 127.0.0.1
+ENTRY_END
+
+; root prime
+ENTRY_BEGIN
+MATCH opcode qtype qname
+REPLY QR AA NOERROR
+ADJUST copy_id
+SECTION QUESTION
+. IN NS
+SECTION ANSWER
+. IN NS root.server.
+SECTION AUTHORITY
+SECTION ADDITIONAL
+root.server. IN A 127.0.0.1
+ENTRY_END
+
diff --git a/contrib/unbound/testdata/svcb.tdir/svcb.test b/contrib/unbound/testdata/svcb.tdir/svcb.test
index 707287d5cf89..17330e08fde6 100644
--- a/contrib/unbound/testdata/svcb.tdir/svcb.test
+++ b/contrib/unbound/testdata/svcb.tdir/svcb.test
@@ -80,7 +80,7 @@ else
fi
-# check all the succes and write them
+# check all the success and write them
if ! $PRE/readzone svcb.success-cases.zone > svcb.success-cases.zone.out
then
echo "Some particular success cases did not succeed to parse"
diff --git a/contrib/unbound/util/config_file.c b/contrib/unbound/util/config_file.c
index 083654ebad4c..413d7e3221dd 100644
--- a/contrib/unbound/util/config_file.c
+++ b/contrib/unbound/util/config_file.c
@@ -328,6 +328,7 @@ config_create(void)
cfg->ratelimit_size = 4*1024*1024;
cfg->ratelimit_for_domain = NULL;
cfg->ratelimit_below_domain = NULL;
+ cfg->outbound_msg_retry = 5;
cfg->ip_ratelimit_factor = 10;
cfg->ratelimit_factor = 10;
cfg->qname_minimisation = 1;
@@ -752,6 +753,7 @@ int config_set_option(struct config_file* cfg, const char* opt,
else S_POW2("ratelimit-slabs:", ratelimit_slabs)
else S_NUMBER_OR_ZERO("ip-ratelimit-factor:", ip_ratelimit_factor)
else S_NUMBER_OR_ZERO("ratelimit-factor:", ratelimit_factor)
+ else S_NUMBER_NONZERO("outbound-msg-retry:", outbound_msg_retry)
else S_SIZET_NONZERO("fast-server-num:", fast_server_num)
else S_NUMBER_OR_ZERO("fast-server-permil:", fast_server_permil)
else S_YNO("qname-minimisation:", qname_minimisation)
@@ -1195,6 +1197,7 @@ config_get_option(struct config_file* cfg, const char* opt,
else O_LS2(opt, "ratelimit-below-domain", ratelimit_below_domain)
else O_DEC(opt, "ip-ratelimit-factor", ip_ratelimit_factor)
else O_DEC(opt, "ratelimit-factor", ratelimit_factor)
+ else O_UNS(opt, "outbound-msg-retry", outbound_msg_retry)
else O_DEC(opt, "fast-server-num", fast_server_num)
else O_DEC(opt, "fast-server-permil", fast_server_permil)
else O_DEC(opt, "val-sig-skew-min", val_sig_skew_min)
diff --git a/contrib/unbound/util/config_file.h b/contrib/unbound/util/config_file.h
index aed6812dafe8..18910bee39fc 100644
--- a/contrib/unbound/util/config_file.h
+++ b/contrib/unbound/util/config_file.h
@@ -578,6 +578,8 @@ struct config_file {
struct config_str2list* ratelimit_below_domain;
/** ratelimit factor, 0 blocks all, 10 allows 1/10 of traffic */
int ratelimit_factor;
+ /** number of retries on outgoing queries */
+ int outbound_msg_retry;
/** minimise outgoing QNAME and hide original QTYPE if possible */
int qname_minimisation;
/** minimise QNAME in strict mode, minimise according to RFC.
@@ -697,6 +699,8 @@ struct config_stub {
int isprime;
/** if forward-first is set (failover to without if fails) */
int isfirst;
+ /** use tcp for queries to this stub */
+ int tcp_upstream;
/** use SSL for queries to this stub */
int ssl_upstream;
/*** no cache */
@@ -1106,7 +1110,7 @@ int cfg_count_numbers(const char* str);
int cfg_parse_memsize(const char* str, size_t* res);
/**
- * Parse nsid from string into binary nsid. nsid is either a hexidecimal
+ * Parse nsid from string into binary nsid. nsid is either a hexadecimal
* string or an ascii string prepended with ascii_ in which case the
* characters after ascii_ are simply copied.
* @param str: the string to parse.
diff --git a/contrib/unbound/util/configlexer.lex b/contrib/unbound/util/configlexer.lex
index b961a84d9401..0fcd74a0cf53 100644
--- a/contrib/unbound/util/configlexer.lex
+++ b/contrib/unbound/util/configlexer.lex
@@ -332,6 +332,7 @@ stub-first{COLON} { YDVAR(1, VAR_STUB_FIRST) }
stub-no-cache{COLON} { YDVAR(1, VAR_STUB_NO_CACHE) }
stub-ssl-upstream{COLON} { YDVAR(1, VAR_STUB_SSL_UPSTREAM) }
stub-tls-upstream{COLON} { YDVAR(1, VAR_STUB_SSL_UPSTREAM) }
+stub-tcp-upstream{COLON} { YDVAR(1, VAR_STUB_TCP_UPSTREAM) }
forward-zone{COLON} { YDVAR(0, VAR_FORWARD_ZONE) }
forward-addr{COLON} { YDVAR(1, VAR_FORWARD_ADDR) }
forward-host{COLON} { YDVAR(1, VAR_FORWARD_HOST) }
@@ -339,6 +340,7 @@ forward-first{COLON} { YDVAR(1, VAR_FORWARD_FIRST) }
forward-no-cache{COLON} { YDVAR(1, VAR_FORWARD_NO_CACHE) }
forward-ssl-upstream{COLON} { YDVAR(1, VAR_FORWARD_SSL_UPSTREAM) }
forward-tls-upstream{COLON} { YDVAR(1, VAR_FORWARD_SSL_UPSTREAM) }
+forward-tcp-upstream{COLON} { YDVAR(1, VAR_FORWARD_TCP_UPSTREAM) }
auth-zone{COLON} { YDVAR(0, VAR_AUTH_ZONE) }
rpz{COLON} { YDVAR(0, VAR_RPZ) }
tags{COLON} { YDVAR(1, VAR_TAGS) }
@@ -500,6 +502,7 @@ ratelimit-for-domain{COLON} { YDVAR(2, VAR_RATELIMIT_FOR_DOMAIN) }
ratelimit-below-domain{COLON} { YDVAR(2, VAR_RATELIMIT_BELOW_DOMAIN) }
ip-ratelimit-factor{COLON} { YDVAR(1, VAR_IP_RATELIMIT_FACTOR) }
ratelimit-factor{COLON} { YDVAR(1, VAR_RATELIMIT_FACTOR) }
+outbound-msg-retry{COLON} { YDVAR(1, VAR_OUTBOUND_MSG_RETRY) }
low-rtt{COLON} { YDVAR(1, VAR_LOW_RTT) }
fast-server-num{COLON} { YDVAR(1, VAR_FAST_SERVER_NUM) }
low-rtt-pct{COLON} { YDVAR(1, VAR_FAST_SERVER_PERMIL) }
diff --git a/contrib/unbound/util/configparser.y b/contrib/unbound/util/configparser.y
index e22d48d41055..1daf853d5749 100644
--- a/contrib/unbound/util/configparser.y
+++ b/contrib/unbound/util/configparser.y
@@ -4,24 +4,24 @@
* Copyright (c) 2001-2006, NLnet Labs. All rights reserved.
*
* Copyright (c) 2007, NLnet Labs. All rights reserved.
- *
+ *
* This software is open source.
- *
+ *
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
- *
+ *
* Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
- *
+ *
* Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
- *
+ *
* Neither the name of the NLNET LABS nor the names of its contributors may
* be used to endorse or promote products derived from this software without
* specific prior written permission.
- *
+ *
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
@@ -88,13 +88,13 @@ extern struct config_parser_state* cfg_parser;
%token VAR_TRUST_ANCHOR_FILE VAR_TRUST_ANCHOR VAR_VAL_OVERRIDE_DATE
%token VAR_BOGUS_TTL VAR_VAL_CLEAN_ADDITIONAL VAR_VAL_PERMISSIVE_MODE
%token VAR_INCOMING_NUM_TCP VAR_MSG_BUFFER_SIZE VAR_KEY_CACHE_SIZE
-%token VAR_KEY_CACHE_SLABS VAR_TRUSTED_KEYS_FILE
-%token VAR_VAL_NSEC3_KEYSIZE_ITERATIONS VAR_USE_SYSLOG
+%token VAR_KEY_CACHE_SLABS VAR_TRUSTED_KEYS_FILE
+%token VAR_VAL_NSEC3_KEYSIZE_ITERATIONS VAR_USE_SYSLOG
%token VAR_OUTGOING_INTERFACE VAR_ROOT_HINTS VAR_DO_NOT_QUERY_LOCALHOST
%token VAR_CACHE_MAX_TTL VAR_HARDEN_DNSSEC_STRIPPED VAR_ACCESS_CONTROL
%token VAR_LOCAL_ZONE VAR_LOCAL_DATA VAR_INTERFACE_AUTOMATIC
%token VAR_STATISTICS_INTERVAL VAR_DO_DAEMONIZE VAR_USE_CAPS_FOR_ID
-%token VAR_STATISTICS_CUMULATIVE VAR_OUTGOING_PORT_PERMIT
+%token VAR_STATISTICS_CUMULATIVE VAR_OUTGOING_PORT_PERMIT
%token VAR_OUTGOING_PORT_AVOID VAR_DLV_ANCHOR_FILE VAR_DLV_ANCHOR
%token VAR_NEG_CACHE_SIZE VAR_HARDEN_REFERRAL_PATH VAR_PRIVATE_ADDRESS
%token VAR_PRIVATE_DOMAIN VAR_REMOTE_CONTROL VAR_CONTROL_ENABLE
@@ -113,6 +113,7 @@ extern struct config_parser_state* cfg_parser;
%token VAR_SSL_UPSTREAM VAR_TCP_AUTH_QUERY_TIMEOUT VAR_SSL_SERVICE_KEY
%token VAR_SSL_SERVICE_PEM VAR_SSL_PORT VAR_FORWARD_FIRST
%token VAR_STUB_SSL_UPSTREAM VAR_FORWARD_SSL_UPSTREAM VAR_TLS_CERT_BUNDLE
+%token VAR_STUB_TCP_UPSTREAM VAR_FORWARD_TCP_UPSTREAM
%token VAR_HTTPS_PORT VAR_HTTP_ENDPOINT VAR_HTTP_MAX_STREAMS
%token VAR_HTTP_QUERY_BUFFER_SIZE VAR_HTTP_RESPONSE_BUFFER_SIZE
%token VAR_HTTP_NODELAY VAR_HTTP_NOTLS_DOWNSTREAM
@@ -138,6 +139,7 @@ extern struct config_parser_state* cfg_parser;
%token VAR_DISABLE_DNSSEC_LAME_CHECK
%token VAR_IP_RATELIMIT VAR_IP_RATELIMIT_SLABS VAR_IP_RATELIMIT_SIZE
%token VAR_RATELIMIT VAR_RATELIMIT_SLABS VAR_RATELIMIT_SIZE
+%token VAR_OUTBOUND_MSG_RETRY
%token VAR_RATELIMIT_FOR_DOMAIN VAR_RATELIMIT_BELOW_DOMAIN
%token VAR_IP_RATELIMIT_FACTOR VAR_RATELIMIT_FACTOR
%token VAR_SEND_CLIENT_SUBNET VAR_CLIENT_SUBNET_ZONE
@@ -189,7 +191,7 @@ extern struct config_parser_state* cfg_parser;
%%
toplevelvars: /* empty */ | toplevelvars toplevelvar ;
toplevelvar: serverstart contents_server | stubstart contents_stub |
- forwardstart contents_forward | pythonstart contents_py |
+ forwardstart contents_forward | pythonstart contents_py |
rcstart contents_rc | dtstart contents_dt | viewstart contents_view |
dnscstart contents_dnsc | cachedbstart contents_cachedb |
ipsetstart contents_ipset | authstart contents_auth |
@@ -203,7 +205,7 @@ force_toplevel: VAR_FORCE_TOPLEVEL
;
/* server: declaration */
serverstart: VAR_SERVER
- {
+ {
OUTYY(("\nP(server:)\n"));
}
;
@@ -215,14 +217,14 @@ content_server: server_num_threads | server_verbosity | server_port |
server_do_udp | server_do_tcp |
server_tcp_mss | server_outgoing_tcp_mss | server_tcp_idle_timeout |
server_tcp_keepalive | server_tcp_keepalive_timeout |
- server_interface | server_chroot | server_username |
+ server_interface | server_chroot | server_username |
server_directory | server_logfile | server_pidfile |
server_msg_cache_size | server_msg_cache_slabs |
- server_num_queries_per_thread | server_rrset_cache_size |
- server_rrset_cache_slabs | server_outgoing_num_tcp |
- server_infra_host_ttl | server_infra_lame_ttl |
+ server_num_queries_per_thread | server_rrset_cache_size |
+ server_rrset_cache_slabs | server_outgoing_num_tcp |
+ server_infra_host_ttl | server_infra_lame_ttl |
server_infra_cache_slabs | server_infra_cache_numhosts |
- server_infra_cache_lame_size | server_target_fetch_policy |
+ server_infra_cache_lame_size | server_target_fetch_policy |
server_harden_short_bufsize | server_harden_large_queries |
server_do_not_query_address | server_hide_identity |
server_hide_version | server_identity | server_version |
@@ -230,22 +232,22 @@ content_server: server_num_threads | server_verbosity | server_port |
server_harden_glue | server_module_conf | server_trust_anchor_file |
server_trust_anchor | server_val_override_date | server_bogus_ttl |
server_val_clean_additional | server_val_permissive_mode |
- server_incoming_num_tcp | server_msg_buffer_size |
- server_key_cache_size | server_key_cache_slabs |
+ server_incoming_num_tcp | server_msg_buffer_size |
+ server_key_cache_size | server_key_cache_slabs |
server_trusted_keys_file | server_val_nsec3_keysize_iterations |
server_use_syslog | server_outgoing_interface | server_root_hints |
server_do_not_query_localhost | server_cache_max_ttl |
server_harden_dnssec_stripped | server_access_control |
server_local_zone | server_local_data | server_interface_automatic |
- server_statistics_interval | server_do_daemonize |
+ server_statistics_interval | server_do_daemonize |
server_use_caps_for_id | server_statistics_cumulative |
server_outgoing_port_permit | server_outgoing_port_avoid |
server_dlv_anchor_file | server_dlv_anchor | server_neg_cache_size |
server_harden_referral_path | server_private_address |
- server_private_domain | server_extended_statistics |
- server_local_data_ptr | server_jostle_timeout |
- server_unwanted_reply_threshold | server_log_time_ascii |
- server_domain_insecure | server_val_sig_skew_min |
+ server_private_domain | server_extended_statistics |
+ server_local_data_ptr | server_jostle_timeout |
+ server_unwanted_reply_threshold | server_log_time_ascii |
+ server_domain_insecure | server_val_sig_skew_min |
server_val_sig_skew_max | server_val_max_restart |
server_cache_min_ttl | server_val_log_level |
server_auto_trust_anchor_file | server_add_holddown |
@@ -269,9 +271,9 @@ content_server: server_num_threads | server_verbosity | server_port |
server_ip_ratelimit_size | server_ratelimit_size |
server_ratelimit_for_domain |
server_ratelimit_below_domain | server_ratelimit_factor |
- server_ip_ratelimit_factor | server_send_client_subnet |
- server_client_subnet_zone | server_client_subnet_always_forward |
- server_client_subnet_opcode |
+ server_ip_ratelimit_factor | server_outbound_msg_retry |
+ server_send_client_subnet | server_client_subnet_zone |
+ server_client_subnet_always_forward | server_client_subnet_opcode |
server_max_client_subnet_ipv4 | server_max_client_subnet_ipv6 |
server_min_client_subnet_ipv4 | server_min_client_subnet_ipv6 |
server_max_ecs_tree_size_ipv4 | server_max_ecs_tree_size_ipv6 |
@@ -312,52 +314,55 @@ content_server: server_num_threads | server_verbosity | server_port |
stubstart: VAR_STUB_ZONE
{
struct config_stub* s;
- OUTYY(("\nP(stub_zone:)\n"));
+ OUTYY(("\nP(stub_zone:)\n"));
s = (struct config_stub*)calloc(1, sizeof(struct config_stub));
if(s) {
s->next = cfg_parser->cfg->stubs;
cfg_parser->cfg->stubs = s;
- } else
+ } else {
yyerror("out of memory");
+ }
}
;
-contents_stub: contents_stub content_stub
+contents_stub: contents_stub content_stub
| ;
content_stub: stub_name | stub_host | stub_addr | stub_prime | stub_first |
- stub_no_cache | stub_ssl_upstream
+ stub_no_cache | stub_ssl_upstream | stub_tcp_upstream
;
forwardstart: VAR_FORWARD_ZONE
{
struct config_stub* s;
- OUTYY(("\nP(forward_zone:)\n"));
+ OUTYY(("\nP(forward_zone:)\n"));
s = (struct config_stub*)calloc(1, sizeof(struct config_stub));
if(s) {
s->next = cfg_parser->cfg->forwards;
cfg_parser->cfg->forwards = s;
- } else
+ } else {
yyerror("out of memory");
+ }
}
;
-contents_forward: contents_forward content_forward
+contents_forward: contents_forward content_forward
| ;
content_forward: forward_name | forward_host | forward_addr | forward_first |
- forward_no_cache | forward_ssl_upstream
+ forward_no_cache | forward_ssl_upstream | forward_tcp_upstream
;
viewstart: VAR_VIEW
{
struct config_view* s;
- OUTYY(("\nP(view:)\n"));
+ OUTYY(("\nP(view:)\n"));
s = (struct config_view*)calloc(1, sizeof(struct config_view));
if(s) {
s->next = cfg_parser->cfg->views;
if(s->next && !s->next->name)
yyerror("view without name");
cfg_parser->cfg->views = s;
- } else
+ } else {
yyerror("out of memory");
+ }
}
;
-contents_view: contents_view content_view
+contents_view: contents_view content_view
| ;
content_view: view_name | view_local_zone | view_local_data | view_first |
view_response_ip | view_response_ip_data | view_local_data_ptr
@@ -365,7 +370,7 @@ content_view: view_name | view_local_zone | view_local_data | view_first |
authstart: VAR_AUTH_ZONE
{
struct config_auth* s;
- OUTYY(("\nP(auth_zone:)\n"));
+ OUTYY(("\nP(auth_zone:)\n"));
s = (struct config_auth*)calloc(1, sizeof(struct config_auth));
if(s) {
s->next = cfg_parser->cfg->auths;
@@ -377,11 +382,12 @@ authstart: VAR_AUTH_ZONE
s->zonemd_check = 0;
s->zonemd_reject_absence = 0;
s->isrpz = 0;
- } else
+ } else {
yyerror("out of memory");
+ }
}
;
-contents_auth: contents_auth content_auth
+contents_auth: contents_auth content_auth
| ;
content_auth: auth_name | auth_zonefile | auth_master | auth_url |
auth_for_downstream | auth_for_upstream | auth_fallback_enabled |
@@ -463,8 +469,9 @@ rpzstart: VAR_RPZ
s->for_upstream = 0;
s->fallback_enabled = 0;
s->isrpz = 1;
- } else
+ } else {
yyerror("out of memory");
+ }
}
;
contents_rpz: contents_rpz content_rpz
@@ -473,27 +480,27 @@ content_rpz: auth_name | auth_zonefile | rpz_tag | auth_master | auth_url |
auth_allow_notify | rpz_action_override | rpz_cname_override |
rpz_log | rpz_log_name
;
-server_num_threads: VAR_NUM_THREADS STRING_ARG
- {
- OUTYY(("P(server_num_threads:%s)\n", $2));
+server_num_threads: VAR_NUM_THREADS STRING_ARG
+ {
+ OUTYY(("P(server_num_threads:%s)\n", $2));
if(atoi($2) == 0 && strcmp($2, "0") != 0)
yyerror("number expected");
else cfg_parser->cfg->num_threads = atoi($2);
free($2);
}
;
-server_verbosity: VAR_VERBOSITY STRING_ARG
- {
- OUTYY(("P(server_verbosity:%s)\n", $2));
+server_verbosity: VAR_VERBOSITY STRING_ARG
+ {
+ OUTYY(("P(server_verbosity:%s)\n", $2));
if(atoi($2) == 0 && strcmp($2, "0") != 0)
yyerror("number expected");
else cfg_parser->cfg->verbosity = atoi($2);
free($2);
}
;
-server_statistics_interval: VAR_STATISTICS_INTERVAL STRING_ARG
- {
- OUTYY(("P(server_statistics_interval:%s)\n", $2));
+server_statistics_interval: VAR_STATISTICS_INTERVAL STRING_ARG
+ {
+ OUTYY(("P(server_statistics_interval:%s)\n", $2));
if(strcmp($2, "") == 0 || strcmp($2, "0") == 0)
cfg_parser->cfg->stat_interval = 0;
else if(atoi($2) == 0)
@@ -529,9 +536,9 @@ server_shm_enable: VAR_SHM_ENABLE STRING_ARG
free($2);
}
;
-server_shm_key: VAR_SHM_KEY STRING_ARG
- {
- OUTYY(("P(server_shm_key:%s)\n", $2));
+server_shm_key: VAR_SHM_KEY STRING_ARG
+ {
+ OUTYY(("P(server_shm_key:%s)\n", $2));
if(strcmp($2, "") == 0 || strcmp($2, "0") == 0)
cfg_parser->cfg->shm_key = 0;
else if(atoi($2) == 0)
@@ -704,7 +711,7 @@ server_interface: VAR_INTERFACE STRING_ARG
OUTYY(("P(server_interface:%s)\n", $2));
if(cfg_parser->cfg->num_ifs == 0)
cfg_parser->cfg->ifs = calloc(1, sizeof(char*));
- else cfg_parser->cfg->ifs = realloc(cfg_parser->cfg->ifs,
+ else cfg_parser->cfg->ifs = realloc(cfg_parser->cfg->ifs,
(cfg_parser->cfg->num_ifs+1)*sizeof(char*));
if(!cfg_parser->cfg->ifs)
yyerror("out of memory");
@@ -717,8 +724,8 @@ server_outgoing_interface: VAR_OUTGOING_INTERFACE STRING_ARG
OUTYY(("P(server_outgoing_interface:%s)\n", $2));
if(cfg_parser->cfg->num_out_ifs == 0)
cfg_parser->cfg->out_ifs = calloc(1, sizeof(char*));
- else cfg_parser->cfg->out_ifs = realloc(
- cfg_parser->cfg->out_ifs,
+ else cfg_parser->cfg->out_ifs = realloc(
+ cfg_parser->cfg->out_ifs,
(cfg_parser->cfg->num_out_ifs+1)*sizeof(char*));
if(!cfg_parser->cfg->out_ifs)
yyerror("out of memory");
@@ -739,7 +746,7 @@ server_outgoing_range: VAR_OUTGOING_RANGE STRING_ARG
server_outgoing_port_permit: VAR_OUTGOING_PORT_PERMIT STRING_ARG
{
OUTYY(("P(server_outgoing_port_permit:%s)\n", $2));
- if(!cfg_mark_ports($2, 1,
+ if(!cfg_mark_ports($2, 1,
cfg_parser->cfg->outgoing_avail_ports, 65536))
yyerror("port number or range (\"low-high\") expected");
free($2);
@@ -748,7 +755,7 @@ server_outgoing_port_permit: VAR_OUTGOING_PORT_PERMIT STRING_ARG
server_outgoing_port_avoid: VAR_OUTGOING_PORT_AVOID STRING_ARG
{
OUTYY(("P(server_outgoing_port_avoid:%s)\n", $2));
- if(!cfg_mark_ports($2, 0,
+ if(!cfg_mark_ports($2, 0,
cfg_parser->cfg->outgoing_avail_ports, 65536))
yyerror("port number or range (\"low-high\") expected");
free($2);
@@ -838,10 +845,10 @@ server_prefer_ip6: VAR_PREFER_IP6 STRING_ARG
server_tcp_mss: VAR_TCP_MSS STRING_ARG
{
OUTYY(("P(server_tcp_mss:%s)\n", $2));
- if(atoi($2) == 0 && strcmp($2, "0") != 0)
- yyerror("number expected");
- else cfg_parser->cfg->tcp_mss = atoi($2);
- free($2);
+ if(atoi($2) == 0 && strcmp($2, "0") != 0)
+ yyerror("number expected");
+ else cfg_parser->cfg->tcp_mss = atoi($2);
+ free($2);
}
;
server_outgoing_tcp_mss: VAR_OUTGOING_TCP_MSS STRING_ARG
@@ -1141,23 +1148,23 @@ server_log_queries: VAR_LOG_QUERIES STRING_ARG
}
;
server_log_replies: VAR_LOG_REPLIES STRING_ARG
- {
- OUTYY(("P(server_log_replies:%s)\n", $2));
- if(strcmp($2, "yes") != 0 && strcmp($2, "no") != 0)
- yyerror("expected yes or no.");
- else cfg_parser->cfg->log_replies = (strcmp($2, "yes")==0);
- free($2);
- }
- ;
+ {
+ OUTYY(("P(server_log_replies:%s)\n", $2));
+ if(strcmp($2, "yes") != 0 && strcmp($2, "no") != 0)
+ yyerror("expected yes or no.");
+ else cfg_parser->cfg->log_replies = (strcmp($2, "yes")==0);
+ free($2);
+ }
+ ;
server_log_tag_queryreply: VAR_LOG_TAG_QUERYREPLY STRING_ARG
- {
- OUTYY(("P(server_log_tag_queryreply:%s)\n", $2));
- if(strcmp($2, "yes") != 0 && strcmp($2, "no") != 0)
- yyerror("expected yes or no.");
- else cfg_parser->cfg->log_tag_queryreply = (strcmp($2, "yes")==0);
- free($2);
- }
- ;
+ {
+ OUTYY(("P(server_log_tag_queryreply:%s)\n", $2));
+ if(strcmp($2, "yes") != 0 && strcmp($2, "no") != 0)
+ yyerror("expected yes or no.");
+ else cfg_parser->cfg->log_tag_queryreply = (strcmp($2, "yes")==0);
+ free($2);
+ }
+ ;
server_log_servfail: VAR_LOG_SERVFAIL STRING_ARG
{
OUTYY(("P(server_log_servfail:%s)\n", $2));
@@ -1168,14 +1175,14 @@ server_log_servfail: VAR_LOG_SERVFAIL STRING_ARG
}
;
server_log_local_actions: VAR_LOG_LOCAL_ACTIONS STRING_ARG
- {
- OUTYY(("P(server_log_local_actions:%s)\n", $2));
- if(strcmp($2, "yes") != 0 && strcmp($2, "no") != 0)
- yyerror("expected yes or no.");
- else cfg_parser->cfg->log_local_actions = (strcmp($2, "yes")==0);
- free($2);
- }
- ;
+ {
+ OUTYY(("P(server_log_local_actions:%s)\n", $2));
+ if(strcmp($2, "yes") != 0 && strcmp($2, "no") != 0)
+ yyerror("expected yes or no.");
+ else cfg_parser->cfg->log_local_actions = (strcmp($2, "yes")==0);
+ free($2);
+ }
+ ;
server_chroot: VAR_CHROOT STRING_ARG
{
OUTYY(("P(server_chroot:%s)\n", $2));
@@ -1209,7 +1216,7 @@ server_directory: VAR_DIRECTORY STRING_ARG
cfg_parser->chroot)) == 0)
d += strlen(cfg_parser->chroot);
if(d[0]) {
- if(chdir(d))
+ if(chdir(d))
log_err("cannot chdir to directory: %s (%s)",
d, strerror(errno));
}
@@ -1402,35 +1409,35 @@ server_so_sndbuf: VAR_SO_SNDBUF STRING_ARG
}
;
server_so_reuseport: VAR_SO_REUSEPORT STRING_ARG
- {
- OUTYY(("P(server_so_reuseport:%s)\n", $2));
- if(strcmp($2, "yes") != 0 && strcmp($2, "no") != 0)
- yyerror("expected yes or no.");
- else cfg_parser->cfg->so_reuseport =
- (strcmp($2, "yes")==0);
- free($2);
- }
- ;
+ {
+ OUTYY(("P(server_so_reuseport:%s)\n", $2));
+ if(strcmp($2, "yes") != 0 && strcmp($2, "no") != 0)
+ yyerror("expected yes or no.");
+ else cfg_parser->cfg->so_reuseport =
+ (strcmp($2, "yes")==0);
+ free($2);
+ }
+ ;
server_ip_transparent: VAR_IP_TRANSPARENT STRING_ARG
- {
- OUTYY(("P(server_ip_transparent:%s)\n", $2));
- if(strcmp($2, "yes") != 0 && strcmp($2, "no") != 0)
- yyerror("expected yes or no.");
- else cfg_parser->cfg->ip_transparent =
- (strcmp($2, "yes")==0);
- free($2);
- }
- ;
+ {
+ OUTYY(("P(server_ip_transparent:%s)\n", $2));
+ if(strcmp($2, "yes") != 0 && strcmp($2, "no") != 0)
+ yyerror("expected yes or no.");
+ else cfg_parser->cfg->ip_transparent =
+ (strcmp($2, "yes")==0);
+ free($2);
+ }
+ ;
server_ip_freebind: VAR_IP_FREEBIND STRING_ARG
- {
- OUTYY(("P(server_ip_freebind:%s)\n", $2));
- if(strcmp($2, "yes") != 0 && strcmp($2, "no") != 0)
- yyerror("expected yes or no.");
- else cfg_parser->cfg->ip_freebind =
- (strcmp($2, "yes")==0);
- free($2);
- }
- ;
+ {
+ OUTYY(("P(server_ip_freebind:%s)\n", $2));
+ if(strcmp($2, "yes") != 0 && strcmp($2, "no") != 0)
+ yyerror("expected yes or no.");
+ else cfg_parser->cfg->ip_freebind =
+ (strcmp($2, "yes")==0);
+ free($2);
+ }
+ ;
server_ip_dscp: VAR_IP_DSCP STRING_ARG
{
OUTYY(("P(server_ip_dscp:%s)\n", $2));
@@ -1488,9 +1495,9 @@ server_msg_cache_size: VAR_MSG_CACHE_SIZE STRING_ARG
server_msg_cache_slabs: VAR_MSG_CACHE_SLABS STRING_ARG
{
OUTYY(("P(server_msg_cache_slabs:%s)\n", $2));
- if(atoi($2) == 0)
+ if(atoi($2) == 0) {
yyerror("number expected");
- else {
+ } else {
cfg_parser->cfg->msg_cache_slabs = atoi($2);
if(!is_pow2(cfg_parser->cfg->msg_cache_slabs))
yyerror("must be a power of 2");
@@ -1539,7 +1546,7 @@ server_unblock_lan_zones: VAR_UNBLOCK_LAN_ZONES STRING_ARG
OUTYY(("P(server_unblock_lan_zones:%s)\n", $2));
if(strcmp($2, "yes") != 0 && strcmp($2, "no") != 0)
yyerror("expected yes or no.");
- else cfg_parser->cfg->unblock_lan_zones =
+ else cfg_parser->cfg->unblock_lan_zones =
(strcmp($2, "yes")==0);
free($2);
}
@@ -1549,7 +1556,7 @@ server_insecure_lan_zones: VAR_INSECURE_LAN_ZONES STRING_ARG
OUTYY(("P(server_insecure_lan_zones:%s)\n", $2));
if(strcmp($2, "yes") != 0 && strcmp($2, "no") != 0)
yyerror("expected yes or no.");
- else cfg_parser->cfg->insecure_lan_zones =
+ else cfg_parser->cfg->insecure_lan_zones =
(strcmp($2, "yes")==0);
free($2);
}
@@ -1565,9 +1572,9 @@ server_rrset_cache_size: VAR_RRSET_CACHE_SIZE STRING_ARG
server_rrset_cache_slabs: VAR_RRSET_CACHE_SLABS STRING_ARG
{
OUTYY(("P(server_rrset_cache_slabs:%s)\n", $2));
- if(atoi($2) == 0)
+ if(atoi($2) == 0) {
yyerror("number expected");
- else {
+ } else {
cfg_parser->cfg->rrset_cache_slabs = atoi($2);
if(!is_pow2(cfg_parser->cfg->rrset_cache_slabs))
yyerror("must be a power of 2");
@@ -1612,9 +1619,9 @@ server_infra_cache_lame_size: VAR_INFRA_CACHE_LAME_SIZE STRING_ARG
server_infra_cache_slabs: VAR_INFRA_CACHE_SLABS STRING_ARG
{
OUTYY(("P(server_infra_cache_slabs:%s)\n", $2));
- if(atoi($2) == 0)
+ if(atoi($2) == 0) {
yyerror("number expected");
- else {
+ } else {
cfg_parser->cfg->infra_cache_slabs = atoi($2);
if(!is_pow2(cfg_parser->cfg->infra_cache_slabs))
yyerror("must be a power of 2");
@@ -1653,7 +1660,7 @@ server_harden_short_bufsize: VAR_HARDEN_SHORT_BUFSIZE STRING_ARG
OUTYY(("P(server_harden_short_bufsize:%s)\n", $2));
if(strcmp($2, "yes") != 0 && strcmp($2, "no") != 0)
yyerror("expected yes or no.");
- else cfg_parser->cfg->harden_short_bufsize =
+ else cfg_parser->cfg->harden_short_bufsize =
(strcmp($2, "yes")==0);
free($2);
}
@@ -1663,7 +1670,7 @@ server_harden_large_queries: VAR_HARDEN_LARGE_QUERIES STRING_ARG
OUTYY(("P(server_harden_large_queries:%s)\n", $2));
if(strcmp($2, "yes") != 0 && strcmp($2, "no") != 0)
yyerror("expected yes or no.");
- else cfg_parser->cfg->harden_large_queries =
+ else cfg_parser->cfg->harden_large_queries =
(strcmp($2, "yes")==0);
free($2);
}
@@ -1673,7 +1680,7 @@ server_harden_glue: VAR_HARDEN_GLUE STRING_ARG
OUTYY(("P(server_harden_glue:%s)\n", $2));
if(strcmp($2, "yes") != 0 && strcmp($2, "no") != 0)
yyerror("expected yes or no.");
- else cfg_parser->cfg->harden_glue =
+ else cfg_parser->cfg->harden_glue =
(strcmp($2, "yes")==0);
free($2);
}
@@ -1683,7 +1690,7 @@ server_harden_dnssec_stripped: VAR_HARDEN_DNSSEC_STRIPPED STRING_ARG
OUTYY(("P(server_harden_dnssec_stripped:%s)\n", $2));
if(strcmp($2, "yes") != 0 && strcmp($2, "no") != 0)
yyerror("expected yes or no.");
- else cfg_parser->cfg->harden_dnssec_stripped =
+ else cfg_parser->cfg->harden_dnssec_stripped =
(strcmp($2, "yes")==0);
free($2);
}
@@ -1693,7 +1700,7 @@ server_harden_below_nxdomain: VAR_HARDEN_BELOW_NXDOMAIN STRING_ARG
OUTYY(("P(server_harden_below_nxdomain:%s)\n", $2));
if(strcmp($2, "yes") != 0 && strcmp($2, "no") != 0)
yyerror("expected yes or no.");
- else cfg_parser->cfg->harden_below_nxdomain =
+ else cfg_parser->cfg->harden_below_nxdomain =
(strcmp($2, "yes")==0);
free($2);
}
@@ -1703,7 +1710,7 @@ server_harden_referral_path: VAR_HARDEN_REFERRAL_PATH STRING_ARG
OUTYY(("P(server_harden_referral_path:%s)\n", $2));
if(strcmp($2, "yes") != 0 && strcmp($2, "no") != 0)
yyerror("expected yes or no.");
- else cfg_parser->cfg->harden_referral_path =
+ else cfg_parser->cfg->harden_referral_path =
(strcmp($2, "yes")==0);
free($2);
}
@@ -1713,7 +1720,7 @@ server_harden_algo_downgrade: VAR_HARDEN_ALGO_DOWNGRADE STRING_ARG
OUTYY(("P(server_harden_algo_downgrade:%s)\n", $2));
if(strcmp($2, "yes") != 0 && strcmp($2, "no") != 0)
yyerror("expected yes or no.");
- else cfg_parser->cfg->harden_algo_downgrade =
+ else cfg_parser->cfg->harden_algo_downgrade =
(strcmp($2, "yes")==0);
free($2);
}
@@ -1723,7 +1730,7 @@ server_use_caps_for_id: VAR_USE_CAPS_FOR_ID STRING_ARG
OUTYY(("P(server_use_caps_for_id:%s)\n", $2));
if(strcmp($2, "yes") != 0 && strcmp($2, "no") != 0)
yyerror("expected yes or no.");
- else cfg_parser->cfg->use_caps_bits_for_id =
+ else cfg_parser->cfg->use_caps_bits_for_id =
(strcmp($2, "yes")==0);
free($2);
}
@@ -1797,7 +1804,7 @@ server_do_not_query_localhost: VAR_DO_NOT_QUERY_LOCALHOST STRING_ARG
OUTYY(("P(server_do_not_query_localhost:%s)\n", $2));
if(strcmp($2, "yes") != 0 && strcmp($2, "no") != 0)
yyerror("expected yes or no.");
- else cfg_parser->cfg->donotquery_localhost =
+ else cfg_parser->cfg->donotquery_localhost =
(strcmp($2, "yes")==0);
free($2);
}
@@ -1808,8 +1815,8 @@ server_access_control: VAR_ACCESS_CONTROL STRING_ARG STRING_ARG
if(strcmp($3, "deny")!=0 && strcmp($3, "refuse")!=0 &&
strcmp($3, "deny_non_local")!=0 &&
strcmp($3, "refuse_non_local")!=0 &&
- strcmp($3, "allow_setrd")!=0 &&
- strcmp($3, "allow")!=0 &&
+ strcmp($3, "allow_setrd")!=0 &&
+ strcmp($3, "allow")!=0 &&
strcmp($3, "allow_snoop")!=0) {
yyerror("expected deny, refuse, deny_non_local, "
"refuse_non_local, allow, allow_setrd or "
@@ -1835,7 +1842,7 @@ server_val_override_date: VAR_VAL_OVERRIDE_DATE STRING_ARG
if(*$2 == '\0' || strcmp($2, "0") == 0) {
cfg_parser->cfg->val_date_override = 0;
} else if(strlen($2) == 14) {
- cfg_parser->cfg->val_date_override =
+ cfg_parser->cfg->val_date_override =
cfg_convert_timeval($2);
if(!cfg_parser->cfg->val_date_override)
yyerror("bad date/time specification");
@@ -1927,7 +1934,7 @@ server_val_clean_additional: VAR_VAL_CLEAN_ADDITIONAL STRING_ARG
OUTYY(("P(server_val_clean_additional:%s)\n", $2));
if(strcmp($2, "yes") != 0 && strcmp($2, "no") != 0)
yyerror("expected yes or no.");
- else cfg_parser->cfg->val_clean_additional =
+ else cfg_parser->cfg->val_clean_additional =
(strcmp($2, "yes")==0);
free($2);
}
@@ -1937,7 +1944,7 @@ server_val_permissive_mode: VAR_VAL_PERMISSIVE_MODE STRING_ARG
OUTYY(("P(server_val_permissive_mode:%s)\n", $2));
if(strcmp($2, "yes") != 0 && strcmp($2, "no") != 0)
yyerror("expected yes or no.");
- else cfg_parser->cfg->val_permissive_mode =
+ else cfg_parser->cfg->val_permissive_mode =
(strcmp($2, "yes")==0);
free($2);
}
@@ -2114,9 +2121,9 @@ server_key_cache_size: VAR_KEY_CACHE_SIZE STRING_ARG
server_key_cache_slabs: VAR_KEY_CACHE_SLABS STRING_ARG
{
OUTYY(("P(server_key_cache_slabs:%s)\n", $2));
- if(atoi($2) == 0)
+ if(atoi($2) == 0) {
yyerror("number expected");
- else {
+ } else {
cfg_parser->cfg->key_cache_slabs = atoi($2);
if(!is_pow2(cfg_parser->cfg->key_cache_slabs))
yyerror("must be a power of 2");
@@ -2171,7 +2178,7 @@ server_local_zone: VAR_LOCAL_ZONE STRING_ARG STRING_ARG
free($3);
#endif
} else {
- if(!cfg_str2list_insert(&cfg_parser->cfg->local_zones,
+ if(!cfg_str2list_insert(&cfg_parser->cfg->local_zones,
$2, $3))
fatal_exit("out of memory adding local-zone");
}
@@ -2379,19 +2386,18 @@ server_response_ip_tag: VAR_RESPONSE_IP_TAG STRING_ARG STRING_ARG
}
}
;
-server_ip_ratelimit: VAR_IP_RATELIMIT STRING_ARG
- {
- OUTYY(("P(server_ip_ratelimit:%s)\n", $2));
+server_ip_ratelimit: VAR_IP_RATELIMIT STRING_ARG
+ {
+ OUTYY(("P(server_ip_ratelimit:%s)\n", $2));
if(atoi($2) == 0 && strcmp($2, "0") != 0)
yyerror("number expected");
else cfg_parser->cfg->ip_ratelimit = atoi($2);
free($2);
}
;
-
-server_ratelimit: VAR_RATELIMIT STRING_ARG
- {
- OUTYY(("P(server_ratelimit:%s)\n", $2));
+server_ratelimit: VAR_RATELIMIT STRING_ARG
+ {
+ OUTYY(("P(server_ratelimit:%s)\n", $2));
if(atoi($2) == 0 && strcmp($2, "0") != 0)
yyerror("number expected");
else cfg_parser->cfg->ratelimit = atoi($2);
@@ -2399,13 +2405,13 @@ server_ratelimit: VAR_RATELIMIT STRING_ARG
}
;
server_ip_ratelimit_size: VAR_IP_RATELIMIT_SIZE STRING_ARG
- {
- OUTYY(("P(server_ip_ratelimit_size:%s)\n", $2));
- if(!cfg_parse_memsize($2, &cfg_parser->cfg->ip_ratelimit_size))
- yyerror("memory size expected");
- free($2);
- }
- ;
+ {
+ OUTYY(("P(server_ip_ratelimit_size:%s)\n", $2));
+ if(!cfg_parse_memsize($2, &cfg_parser->cfg->ip_ratelimit_size))
+ yyerror("memory size expected");
+ free($2);
+ }
+ ;
server_ratelimit_size: VAR_RATELIMIT_SIZE STRING_ARG
{
OUTYY(("P(server_ratelimit_size:%s)\n", $2));
@@ -2415,24 +2421,24 @@ server_ratelimit_size: VAR_RATELIMIT_SIZE STRING_ARG
}
;
server_ip_ratelimit_slabs: VAR_IP_RATELIMIT_SLABS STRING_ARG
- {
- OUTYY(("P(server_ip_ratelimit_slabs:%s)\n", $2));
- if(atoi($2) == 0)
- yyerror("number expected");
- else {
- cfg_parser->cfg->ip_ratelimit_slabs = atoi($2);
- if(!is_pow2(cfg_parser->cfg->ip_ratelimit_slabs))
- yyerror("must be a power of 2");
- }
- free($2);
- }
- ;
+ {
+ OUTYY(("P(server_ip_ratelimit_slabs:%s)\n", $2));
+ if(atoi($2) == 0) {
+ yyerror("number expected");
+ } else {
+ cfg_parser->cfg->ip_ratelimit_slabs = atoi($2);
+ if(!is_pow2(cfg_parser->cfg->ip_ratelimit_slabs))
+ yyerror("must be a power of 2");
+ }
+ free($2);
+ }
+ ;
server_ratelimit_slabs: VAR_RATELIMIT_SLABS STRING_ARG
{
OUTYY(("P(server_ratelimit_slabs:%s)\n", $2));
- if(atoi($2) == 0)
+ if(atoi($2) == 0) {
yyerror("number expected");
- else {
+ } else {
cfg_parser->cfg->ratelimit_slabs = atoi($2);
if(!is_pow2(cfg_parser->cfg->ratelimit_slabs))
yyerror("must be a power of 2");
@@ -2470,42 +2476,51 @@ server_ratelimit_below_domain: VAR_RATELIMIT_BELOW_DOMAIN STRING_ARG STRING_ARG
}
}
;
-server_ip_ratelimit_factor: VAR_IP_RATELIMIT_FACTOR STRING_ARG
- {
- OUTYY(("P(server_ip_ratelimit_factor:%s)\n", $2));
- if(atoi($2) == 0 && strcmp($2, "0") != 0)
- yyerror("number expected");
- else cfg_parser->cfg->ip_ratelimit_factor = atoi($2);
- free($2);
+server_ip_ratelimit_factor: VAR_IP_RATELIMIT_FACTOR STRING_ARG
+ {
+ OUTYY(("P(server_ip_ratelimit_factor:%s)\n", $2));
+ if(atoi($2) == 0 && strcmp($2, "0") != 0)
+ yyerror("number expected");
+ else cfg_parser->cfg->ip_ratelimit_factor = atoi($2);
+ free($2);
}
;
-server_ratelimit_factor: VAR_RATELIMIT_FACTOR STRING_ARG
- {
- OUTYY(("P(server_ratelimit_factor:%s)\n", $2));
+server_ratelimit_factor: VAR_RATELIMIT_FACTOR STRING_ARG
+ {
+ OUTYY(("P(server_ratelimit_factor:%s)\n", $2));
if(atoi($2) == 0 && strcmp($2, "0") != 0)
yyerror("number expected");
else cfg_parser->cfg->ratelimit_factor = atoi($2);
free($2);
}
;
-server_low_rtt: VAR_LOW_RTT STRING_ARG
- {
+server_outbound_msg_retry: VAR_OUTBOUND_MSG_RETRY STRING_ARG
+ {
+ OUTYY(("P(server_outbound_msg_retry:%s)\n", $2));
+ if(atoi($2) == 0 && strcmp($2, "0") != 0)
+ yyerror("number expected");
+ else cfg_parser->cfg->outbound_msg_retry = atoi($2);
+ free($2);
+ }
+ ;
+server_low_rtt: VAR_LOW_RTT STRING_ARG
+ {
OUTYY(("P(low-rtt option is deprecated, use fast-server-num instead)\n"));
free($2);
}
;
-server_fast_server_num: VAR_FAST_SERVER_NUM STRING_ARG
- {
- OUTYY(("P(server_fast_server_num:%s)\n", $2));
+server_fast_server_num: VAR_FAST_SERVER_NUM STRING_ARG
+ {
+ OUTYY(("P(server_fast_server_num:%s)\n", $2));
if(atoi($2) <= 0)
yyerror("number expected");
else cfg_parser->cfg->fast_server_num = atoi($2);
free($2);
}
;
-server_fast_server_permil: VAR_FAST_SERVER_PERMIL STRING_ARG
- {
- OUTYY(("P(server_fast_server_permil:%s)\n", $2));
+server_fast_server_permil: VAR_FAST_SERVER_PERMIL STRING_ARG
+ {
+ OUTYY(("P(server_fast_server_permil:%s)\n", $2));
if(atoi($2) == 0 && strcmp($2, "0") != 0)
yyerror("number expected");
else cfg_parser->cfg->fast_server_permil = atoi($2);
@@ -2517,7 +2532,7 @@ server_qname_minimisation: VAR_QNAME_MINIMISATION STRING_ARG
OUTYY(("P(server_qname_minimisation:%s)\n", $2));
if(strcmp($2, "yes") != 0 && strcmp($2, "no") != 0)
yyerror("expected yes or no.");
- else cfg_parser->cfg->qname_minimisation =
+ else cfg_parser->cfg->qname_minimisation =
(strcmp($2, "yes")==0);
free($2);
}
@@ -2527,7 +2542,7 @@ server_qname_minimisation_strict: VAR_QNAME_MINIMISATION_STRICT STRING_ARG
OUTYY(("P(server_qname_minimisation_strict:%s)\n", $2));
if(strcmp($2, "yes") != 0 && strcmp($2, "no") != 0)
yyerror("expected yes or no.");
- else cfg_parser->cfg->qname_minimisation_strict =
+ else cfg_parser->cfg->qname_minimisation_strict =
(strcmp($2, "yes")==0);
free($2);
}
@@ -2716,17 +2731,27 @@ stub_ssl_upstream: VAR_STUB_SSL_UPSTREAM STRING_ARG
OUTYY(("P(stub-ssl-upstream:%s)\n", $2));
if(strcmp($2, "yes") != 0 && strcmp($2, "no") != 0)
yyerror("expected yes or no.");
- else cfg_parser->cfg->stubs->ssl_upstream =
+ else cfg_parser->cfg->stubs->ssl_upstream =
(strcmp($2, "yes")==0);
free($2);
}
;
+stub_tcp_upstream: VAR_STUB_TCP_UPSTREAM STRING_ARG
+ {
+ OUTYY(("P(stub-tcp-upstream:%s)\n", $2));
+ if(strcmp($2, "yes") != 0 && strcmp($2, "no") != 0)
+ yyerror("expected yes or no.");
+ else cfg_parser->cfg->stubs->tcp_upstream =
+ (strcmp($2, "yes")==0);
+ free($2);
+ }
+ ;
stub_prime: VAR_STUB_PRIME STRING_ARG
{
OUTYY(("P(stub-prime:%s)\n", $2));
if(strcmp($2, "yes") != 0 && strcmp($2, "no") != 0)
yyerror("expected yes or no.");
- else cfg_parser->cfg->stubs->isprime =
+ else cfg_parser->cfg->stubs->isprime =
(strcmp($2, "yes")==0);
free($2);
}
@@ -2778,11 +2803,21 @@ forward_ssl_upstream: VAR_FORWARD_SSL_UPSTREAM STRING_ARG
OUTYY(("P(forward-ssl-upstream:%s)\n", $2));
if(strcmp($2, "yes") != 0 && strcmp($2, "no") != 0)
yyerror("expected yes or no.");
- else cfg_parser->cfg->forwards->ssl_upstream =
+ else cfg_parser->cfg->forwards->ssl_upstream =
(strcmp($2, "yes")==0);
free($2);
}
;
+forward_tcp_upstream: VAR_FORWARD_TCP_UPSTREAM STRING_ARG
+ {
+ OUTYY(("P(forward-tcp-upstream:%s)\n", $2));
+ if(strcmp($2, "yes") != 0 && strcmp($2, "no") != 0)
+ yyerror("expected yes or no.");
+ else cfg_parser->cfg->forwards->tcp_upstream =
+ (strcmp($2, "yes")==0);
+ free($2);
+ }
+ ;
auth_name: VAR_NAME STRING_ARG
{
OUTYY(("P(name:%s)\n", $2));
@@ -2922,7 +2957,7 @@ view_local_zone: VAR_LOCAL_ZONE STRING_ARG STRING_ARG
#endif
} else {
if(!cfg_str2list_insert(
- &cfg_parser->cfg->views->local_zones,
+ &cfg_parser->cfg->views->local_zones,
$2, $3))
fatal_exit("out of memory adding local-zone");
}
@@ -2979,11 +3014,11 @@ view_first: VAR_VIEW_FIRST STRING_ARG
}
;
rcstart: VAR_REMOTE_CONTROL
- {
- OUTYY(("\nP(remote-control:)\n"));
+ {
+ OUTYY(("\nP(remote-control:)\n"));
}
;
-contents_rc: contents_rc content_rc
+contents_rc: contents_rc content_rc
| ;
content_rc: rc_control_enable | rc_control_interface | rc_control_port |
rc_server_key_file | rc_server_cert_file | rc_control_key_file |
@@ -2994,7 +3029,7 @@ rc_control_enable: VAR_CONTROL_ENABLE STRING_ARG
OUTYY(("P(control_enable:%s)\n", $2));
if(strcmp($2, "yes") != 0 && strcmp($2, "no") != 0)
yyerror("expected yes or no.");
- else cfg_parser->cfg->remote_control_enable =
+ else cfg_parser->cfg->remote_control_enable =
(strcmp($2, "yes")==0);
free($2);
}
@@ -3233,8 +3268,8 @@ dt_dnstap_log_forwarder_response_messages: VAR_DNSTAP_LOG_FORWARDER_RESPONSE_MES
}
;
pythonstart: VAR_PYTHON
- {
- OUTYY(("\nP(python:)\n"));
+ {
+ OUTYY(("\nP(python:)\n"));
}
;
contents_py: contents_py content_py
@@ -3365,44 +3400,44 @@ dnsc_dnscrypt_secret_key: VAR_DNSCRYPT_SECRET_KEY STRING_ARG
;
dnsc_dnscrypt_shared_secret_cache_size: VAR_DNSCRYPT_SHARED_SECRET_CACHE_SIZE STRING_ARG
{
- OUTYY(("P(dnscrypt_shared_secret_cache_size:%s)\n", $2));
- if(!cfg_parse_memsize($2, &cfg_parser->cfg->dnscrypt_shared_secret_cache_size))
- yyerror("memory size expected");
- free($2);
+ OUTYY(("P(dnscrypt_shared_secret_cache_size:%s)\n", $2));
+ if(!cfg_parse_memsize($2, &cfg_parser->cfg->dnscrypt_shared_secret_cache_size))
+ yyerror("memory size expected");
+ free($2);
}
;
dnsc_dnscrypt_shared_secret_cache_slabs: VAR_DNSCRYPT_SHARED_SECRET_CACHE_SLABS STRING_ARG
{
- OUTYY(("P(dnscrypt_shared_secret_cache_slabs:%s)\n", $2));
- if(atoi($2) == 0)
- yyerror("number expected");
- else {
- cfg_parser->cfg->dnscrypt_shared_secret_cache_slabs = atoi($2);
- if(!is_pow2(cfg_parser->cfg->dnscrypt_shared_secret_cache_slabs))
- yyerror("must be a power of 2");
- }
- free($2);
+ OUTYY(("P(dnscrypt_shared_secret_cache_slabs:%s)\n", $2));
+ if(atoi($2) == 0) {
+ yyerror("number expected");
+ } else {
+ cfg_parser->cfg->dnscrypt_shared_secret_cache_slabs = atoi($2);
+ if(!is_pow2(cfg_parser->cfg->dnscrypt_shared_secret_cache_slabs))
+ yyerror("must be a power of 2");
+ }
+ free($2);
}
;
dnsc_dnscrypt_nonce_cache_size: VAR_DNSCRYPT_NONCE_CACHE_SIZE STRING_ARG
{
- OUTYY(("P(dnscrypt_nonce_cache_size:%s)\n", $2));
- if(!cfg_parse_memsize($2, &cfg_parser->cfg->dnscrypt_nonce_cache_size))
- yyerror("memory size expected");
- free($2);
+ OUTYY(("P(dnscrypt_nonce_cache_size:%s)\n", $2));
+ if(!cfg_parse_memsize($2, &cfg_parser->cfg->dnscrypt_nonce_cache_size))
+ yyerror("memory size expected");
+ free($2);
}
;
dnsc_dnscrypt_nonce_cache_slabs: VAR_DNSCRYPT_NONCE_CACHE_SLABS STRING_ARG
{
- OUTYY(("P(dnscrypt_nonce_cache_slabs:%s)\n", $2));
- if(atoi($2) == 0)
- yyerror("number expected");
- else {
- cfg_parser->cfg->dnscrypt_nonce_cache_slabs = atoi($2);
- if(!is_pow2(cfg_parser->cfg->dnscrypt_nonce_cache_slabs))
- yyerror("must be a power of 2");
- }
- free($2);
+ OUTYY(("P(dnscrypt_nonce_cache_slabs:%s)\n", $2));
+ if(atoi($2) == 0) {
+ yyerror("number expected");
+ } else {
+ cfg_parser->cfg->dnscrypt_nonce_cache_slabs = atoi($2);
+ if(!is_pow2(cfg_parser->cfg->dnscrypt_nonce_cache_slabs))
+ yyerror("must be a power of 2");
+ }
+ free($2);
}
;
cachedbstart: VAR_CACHEDB
diff --git a/contrib/unbound/util/data/msgencode.c b/contrib/unbound/util/data/msgencode.c
index 5f297b551bfb..fe21cfb86bd1 100644
--- a/contrib/unbound/util/data/msgencode.c
+++ b/contrib/unbound/util/data/msgencode.c
@@ -796,7 +796,10 @@ calc_edns_field_size(struct edns_data* edns)
struct edns_option* opt;
if(!edns || !edns->edns_present)
return 0;
- for(opt = edns->opt_list; opt; opt = opt->next) {
+ for(opt = edns->opt_list_inplace_cb_out; opt; opt = opt->next) {
+ rdatalen += 4 + opt->opt_len;
+ }
+ for(opt = edns->opt_list_out; opt; opt = opt->next) {
rdatalen += 4 + opt->opt_len;
}
/* domain root '.' + type + class + ttl + rdatalen */
@@ -827,7 +830,17 @@ attach_edns_record_max_msg_sz(sldns_buffer* pkt, struct edns_data* edns,
rdatapos = sldns_buffer_position(pkt);
sldns_buffer_write_u16(pkt, 0); /* rdatalen */
/* write rdata */
- for(opt=edns->opt_list; opt; opt=opt->next) {
+ for(opt=edns->opt_list_inplace_cb_out; opt; opt=opt->next) {
+ if (opt->opt_code == LDNS_EDNS_PADDING) {
+ padding_option = opt;
+ continue;
+ }
+ sldns_buffer_write_u16(pkt, opt->opt_code);
+ sldns_buffer_write_u16(pkt, opt->opt_len);
+ if(opt->opt_len != 0)
+ sldns_buffer_write(pkt, opt->opt_data, opt->opt_len);
+ }
+ for(opt=edns->opt_list_out; opt; opt=opt->next) {
if (opt->opt_code == LDNS_EDNS_PADDING) {
padding_option = opt;
continue;
@@ -860,8 +873,7 @@ attach_edns_record_max_msg_sz(sldns_buffer* pkt, struct edns_data* edns,
sldns_buffer_skip(pkt, pad_sz);
}
}
- if(edns->opt_list)
- sldns_buffer_write_u16_at(pkt, rdatapos,
+ sldns_buffer_write_u16_at(pkt, rdatapos,
sldns_buffer_position(pkt)-rdatapos-2);
sldns_buffer_flip(pkt);
}
diff --git a/contrib/unbound/util/data/msgparse.c b/contrib/unbound/util/data/msgparse.c
index 6ee5559db07b..a600a8c60151 100644
--- a/contrib/unbound/util/data/msgparse.c
+++ b/contrib/unbound/util/data/msgparse.c
@@ -37,10 +37,12 @@
* Routines for message parsing a packet buffer to a descriptive structure.
*/
#include "config.h"
+#include "util/config_file.h"
#include "util/data/msgparse.h"
#include "util/data/msgreply.h"
#include "util/data/dname.h"
#include "util/data/packed_rrset.h"
+#include "util/netevent.h"
#include "util/storage/lookup3.h"
#include "util/regional.h"
#include "sldns/rrdef.h"
@@ -938,11 +940,40 @@ parse_packet(sldns_buffer* pkt, struct msg_parse* msg, struct regional* region)
return 0;
}
+static int
+edns_opt_list_append_keepalive(struct edns_option** list, int msec,
+ struct regional* region)
+{
+ uint8_t data[2]; /* For keepalive value */
+ data[0] = (uint8_t)((msec >> 8) & 0xff);
+ data[1] = (uint8_t)(msec & 0xff);
+ return edns_opt_list_append(list, LDNS_EDNS_KEEPALIVE, sizeof(data),
+ data, region);
+}
+
/** parse EDNS options from EDNS wireformat rdata */
static int
-parse_edns_options(uint8_t* rdata_ptr, size_t rdata_len,
- struct edns_data* edns, struct regional* region)
+parse_edns_options_from_query(uint8_t* rdata_ptr, size_t rdata_len,
+ struct edns_data* edns, struct config_file* cfg, struct comm_point* c,
+ struct regional* region)
{
+ /* To respond with a Keepalive option, the client connection must have
+ * received one message with a TCP Keepalive EDNS option, and that
+ * option must have 0 length data. Subsequent messages sent on that
+ * connection will have a TCP Keepalive option.
+ *
+ * In the if-statement below, the option is added unsolicited. This
+ * means that the client has sent an KEEPALIVE option earlier. We know
+ * here this is true, because c->tcp_keepalive is set.
+ */
+ if (cfg && cfg->do_tcp_keepalive && c && c->type != comm_udp && c->tcp_keepalive) {
+ if(!edns_opt_list_append_keepalive(&edns->opt_list_out,
+ c->tcp_timeout_msec / 100, region)) {
+ log_err("out of memory");
+ return LDNS_RCODE_SERVFAIL;
+ }
+ }
+
/* while still more options, and have code+len to read */
/* ignores partial content (i.e. rdata len 3) */
while(rdata_len >= 4) {
@@ -952,20 +983,81 @@ parse_edns_options(uint8_t* rdata_ptr, size_t rdata_len,
rdata_len -= 4;
if(opt_len > rdata_len)
break; /* option code partial */
- if(!edns_opt_append(edns, region, opt_code, opt_len,
- rdata_ptr)) {
+
+ /* handle parse time edns options here */
+ switch(opt_code) {
+ case LDNS_EDNS_NSID:
+ if (!cfg || !cfg->nsid)
+ break;
+ if(!edns_opt_list_append(&edns->opt_list_out,
+ LDNS_EDNS_NSID, cfg->nsid_len,
+ cfg->nsid, region)) {
+ log_err("out of memory");
+ return LDNS_RCODE_SERVFAIL;
+ }
+ break;
+
+ case LDNS_EDNS_KEEPALIVE:
+ /* To respond with a Keepalive option, the client
+ * connection must have received one message with a TCP
+ * Keepalive EDNS option, and that option must have 0
+ * length data. Subsequent messages sent on that
+ * connection will have a TCP Keepalive option.
+ *
+ * This should be the first time the client sends this
+ * option, so c->tcp_keepalive is not set.
+ * Besides adding the reply KEEPALIVE option,
+ * c->tcp_keepalive will be set so that the
+ * option will be added unsolicited in subsequent
+ * responses (see the comment above the if-statement
+ * at the start of this function).
+ */
+ if (!cfg || !cfg->do_tcp_keepalive || !c ||
+ c->type == comm_udp || c->tcp_keepalive)
+ break;
+ if(opt_len) {
+ verbose(VERB_ALGO, "query with bad edns keepalive.");
+ return LDNS_RCODE_FORMERR;
+ }
+ if(!edns_opt_list_append_keepalive(&edns->opt_list_out,
+ c->tcp_timeout_msec / 100,
+ region)) {
+ log_err("out of memory");
+ return LDNS_RCODE_SERVFAIL;
+ }
+ c->tcp_keepalive = 1;
+ break;
+
+ case LDNS_EDNS_PADDING:
+ if(!cfg || !cfg->pad_responses ||
+ !c || c->type != comm_tcp ||!c->ssl)
+ break;
+ if(!edns_opt_list_append(&edns->opt_list_out,
+ LDNS_EDNS_PADDING,
+ 0, NULL, region)) {
+ log_err("out of memory");
+ return LDNS_RCODE_SERVFAIL;
+ }
+ edns->padding_block_size = cfg->pad_responses_block_size;
+ break;
+
+ default:
+ break;
+ }
+ if(!edns_opt_list_append(&edns->opt_list_in,
+ opt_code, opt_len, rdata_ptr, region)) {
log_err("out of memory");
- return 0;
+ return LDNS_RCODE_SERVFAIL;
}
rdata_ptr += opt_len;
rdata_len -= opt_len;
}
- return 1;
+ return LDNS_RCODE_NOERROR;
}
int
-parse_extract_edns(struct msg_parse* msg, struct edns_data* edns,
- struct regional* region)
+parse_extract_edns_from_response_msg(struct msg_parse* msg,
+ struct edns_data* edns, struct regional* region)
{
struct rrset_parse* rrset = msg->rrset_first;
struct rrset_parse* prev = 0;
@@ -1019,18 +1111,35 @@ parse_extract_edns(struct msg_parse* msg, struct edns_data* edns,
edns->edns_version = found->rr_last->ttl_data[1];
edns->bits = sldns_read_uint16(&found->rr_last->ttl_data[2]);
edns->udp_size = ntohs(found->rrset_class);
- edns->opt_list = NULL;
+ edns->opt_list_in = NULL;
+ edns->opt_list_out = NULL;
+ edns->opt_list_inplace_cb_out = NULL;
edns->padding_block_size = 0;
/* take the options */
rdata_len = found->rr_first->size-2;
rdata_ptr = found->rr_first->ttl_data+6;
- if(!parse_edns_options(rdata_ptr, rdata_len, edns, region))
- return 0;
- /* ignore rrsigs */
+ /* while still more options, and have code+len to read */
+ /* ignores partial content (i.e. rdata len 3) */
+ while(rdata_len >= 4) {
+ uint16_t opt_code = sldns_read_uint16(rdata_ptr);
+ uint16_t opt_len = sldns_read_uint16(rdata_ptr+2);
+ rdata_ptr += 4;
+ rdata_len -= 4;
+ if(opt_len > rdata_len)
+ break; /* option code partial */
- return 0;
+ if(!edns_opt_list_append(&edns->opt_list_in,
+ opt_code, opt_len, rdata_ptr, region)) {
+ log_err("out of memory");
+ break;
+ }
+ rdata_ptr += opt_len;
+ rdata_len -= opt_len;
+ }
+ /* ignore rrsigs */
+ return LDNS_RCODE_NOERROR;
}
/** skip RR in packet */
@@ -1060,8 +1169,8 @@ skip_pkt_rrs(sldns_buffer* pkt, int num)
}
int
-parse_edns_from_pkt(sldns_buffer* pkt, struct edns_data* edns,
- struct regional* region)
+parse_edns_from_query_pkt(sldns_buffer* pkt, struct edns_data* edns,
+ struct config_file* cfg, struct comm_point* c, struct regional* region)
{
size_t rdata_len;
uint8_t* rdata_ptr;
@@ -1093,7 +1202,9 @@ parse_edns_from_pkt(sldns_buffer* pkt, struct edns_data* edns,
edns->ext_rcode = sldns_buffer_read_u8(pkt); /* ttl used for bits */
edns->edns_version = sldns_buffer_read_u8(pkt);
edns->bits = sldns_buffer_read_u16(pkt);
- edns->opt_list = NULL;
+ edns->opt_list_in = NULL;
+ edns->opt_list_out = NULL;
+ edns->opt_list_inplace_cb_out = NULL;
edns->padding_block_size = 0;
/* take the options */
@@ -1101,12 +1212,9 @@ parse_edns_from_pkt(sldns_buffer* pkt, struct edns_data* edns,
if(sldns_buffer_remaining(pkt) < rdata_len)
return LDNS_RCODE_FORMERR;
rdata_ptr = sldns_buffer_current(pkt);
- if(!parse_edns_options(rdata_ptr, rdata_len, edns, region))
- return LDNS_RCODE_SERVFAIL;
-
/* ignore rrsigs */
-
- return 0;
+ return parse_edns_options_from_query(rdata_ptr, rdata_len, edns, cfg,
+ c, region);
}
void
diff --git a/contrib/unbound/util/data/msgparse.h b/contrib/unbound/util/data/msgparse.h
index d2fd9c806657..4c0559a739a4 100644
--- a/contrib/unbound/util/data/msgparse.h
+++ b/contrib/unbound/util/data/msgparse.h
@@ -70,6 +70,8 @@ struct rrset_parse;
struct rr_parse;
struct regional;
struct edns_option;
+struct config_file;
+struct comm_point;
/** number of buckets in parse rrset hash table. Must be power of 2. */
#define PARSE_TABLE_SIZE 32
@@ -225,8 +227,15 @@ struct edns_data {
uint16_t bits;
/** UDP reassembly size. */
uint16_t udp_size;
- /** rdata element list, or NULL if none */
- struct edns_option* opt_list;
+ /** rdata element list of options of an incoming packet created at
+ * parse time, or NULL if none */
+ struct edns_option* opt_list_in;
+ /** rdata element list of options to encode for outgoing packets,
+ * or NULL if none */
+ struct edns_option* opt_list_out;
+ /** rdata element list of outgoing edns options from modules
+ * or NULL if none */
+ struct edns_option* opt_list_inplace_cb_out;
/** block size to pad */
uint16_t padding_block_size;
};
@@ -281,8 +290,8 @@ int parse_packet(struct sldns_buffer* pkt, struct msg_parse* msg,
* @return: 0 on success. or an RCODE on an error.
* RCODE formerr if OPT in wrong section, and so on.
*/
-int parse_extract_edns(struct msg_parse* msg, struct edns_data* edns,
- struct regional* region);
+int parse_extract_edns_from_response_msg(struct msg_parse* msg,
+ struct edns_data* edns, struct regional* region);
/**
* If EDNS data follows a query section, extract it and initialize edns struct.
@@ -290,12 +299,14 @@ int parse_extract_edns(struct msg_parse* msg, struct edns_data* edns,
* section. At end, right after EDNS data or no movement if failed.
* @param edns: the edns data allocated by the caller. Does not have to be
* initialised.
+ * @param cfg: the configuration (with nsid value etc.)
+ * @param c: commpoint to determine transport (if needed)
* @param region: region to alloc results in (edns option contents)
* @return: 0 on success, or an RCODE on error.
* RCODE formerr if OPT is badly formatted and so on.
*/
-int parse_edns_from_pkt(struct sldns_buffer* pkt, struct edns_data* edns,
- struct regional* region);
+int parse_edns_from_query_pkt(struct sldns_buffer* pkt, struct edns_data* edns,
+ struct config_file* cfg, struct comm_point* c, struct regional* region);
/**
* Calculate hash value for rrset in packet.
diff --git a/contrib/unbound/util/data/msgreply.c b/contrib/unbound/util/data/msgreply.c
index 00272fd1c64e..ec46e4724780 100644
--- a/contrib/unbound/util/data/msgreply.c
+++ b/contrib/unbound/util/data/msgreply.c
@@ -166,6 +166,32 @@ reply_info_alloc_rrset_keys(struct reply_info* rep, struct alloc_cache* alloc,
return 1;
}
+struct reply_info *
+make_new_reply_info(const struct reply_info* rep, struct regional* region,
+ size_t an_numrrsets, size_t copy_rrsets)
+{
+ struct reply_info* new_rep;
+ size_t i;
+
+ /* create a base struct. we specify 'insecure' security status as
+ * the modified response won't be DNSSEC-valid. In our faked response
+ * the authority and additional sections will be empty (except possible
+ * EDNS0 OPT RR in the additional section appended on sending it out),
+ * so the total number of RRsets is an_numrrsets. */
+ new_rep = construct_reply_info_base(region, rep->flags,
+ rep->qdcount, rep->ttl, rep->prefetch_ttl,
+ rep->serve_expired_ttl, an_numrrsets, 0, 0, an_numrrsets,
+ sec_status_insecure);
+ if(!new_rep)
+ return NULL;
+ if(!reply_info_alloc_rrset_keys(new_rep, NULL, region))
+ return NULL;
+ for(i=0; i<copy_rrsets; i++)
+ new_rep->rrsets[i] = rep->rrsets[i];
+
+ return new_rep;
+}
+
/** find the minimumttl in the rdata of SOA record */
static time_t
soa_find_minttl(struct rr_parse* rr)
@@ -196,13 +222,17 @@ rdata_copy(sldns_buffer* pkt, struct packed_rrset_data* data, uint8_t* to,
* minimum-ttl in the rdata of the SOA record */
if(*rr_ttl > soa_find_minttl(rr))
*rr_ttl = soa_find_minttl(rr);
- if(*rr_ttl > MAX_NEG_TTL)
- *rr_ttl = MAX_NEG_TTL;
}
if(!SERVE_ORIGINAL_TTL && (*rr_ttl < MIN_TTL))
*rr_ttl = MIN_TTL;
if(!SERVE_ORIGINAL_TTL && (*rr_ttl > MAX_TTL))
*rr_ttl = MAX_TTL;
+ if(type == LDNS_RR_TYPE_SOA && section == LDNS_SECTION_AUTHORITY) {
+ /* max neg ttl overrides the min and max ttl of everything
+ * else, it is for a more specific record */
+ if(*rr_ttl > MAX_NEG_TTL)
+ *rr_ttl = MAX_NEG_TTL;
+ }
if(*rr_ttl < data->ttl)
data->ttl = *rr_ttl;
@@ -488,14 +518,13 @@ int reply_info_parse(sldns_buffer* pkt, struct alloc_cache* alloc,
if((ret = parse_packet(pkt, msg, region)) != 0) {
return ret;
}
- if((ret = parse_extract_edns(msg, edns, region)) != 0)
+ if((ret = parse_extract_edns_from_response_msg(msg, edns, region)) != 0)
return ret;
/* parse OK, allocate return structures */
/* this also performs dname decompression */
if(!parse_create_msg(pkt, msg, alloc, qinf, rep, NULL)) {
query_info_clear(qinf);
- reply_info_parsedelete(*rep, alloc);
*rep = NULL;
return LDNS_RCODE_SERVFAIL;
}
@@ -960,34 +989,6 @@ parse_reply_in_temp_region(sldns_buffer* pkt, struct regional* region,
return rep;
}
-int edns_opt_append(struct edns_data* edns, struct regional* region,
- uint16_t code, size_t len, uint8_t* data)
-{
- struct edns_option** prevp;
- struct edns_option* opt;
-
- /* allocate new element */
- opt = (struct edns_option*)regional_alloc(region, sizeof(*opt));
- if(!opt)
- return 0;
- opt->next = NULL;
- opt->opt_code = code;
- opt->opt_len = len;
- opt->opt_data = NULL;
- if(len > 0) {
- opt->opt_data = regional_alloc_init(region, data, len);
- if(!opt->opt_data)
- return 0;
- }
-
- /* append at end of list */
- prevp = &edns->opt_list;
- while(*prevp != NULL)
- prevp = &((*prevp)->next);
- *prevp = opt;
- return 1;
-}
-
int edns_opt_list_append(struct edns_option** list, uint16_t code, size_t len,
uint8_t* data, struct regional* region)
{
@@ -1068,7 +1069,7 @@ static int inplace_cb_reply_call_generic(
(void)(*(inplace_cb_reply_func_type*)cb->cb)(qinfo, qstate, rep,
rcode, edns, &opt_list_out, repinfo, region, start_time, cb->id, cb->cb_arg);
}
- edns->opt_list = opt_list_out;
+ edns->opt_list_inplace_cb_out = opt_list_out;
return 1;
}
diff --git a/contrib/unbound/util/data/msgreply.h b/contrib/unbound/util/data/msgreply.h
index c6b220ed8d71..81c763fc7c3a 100644
--- a/contrib/unbound/util/data/msgreply.h
+++ b/contrib/unbound/util/data/msgreply.h
@@ -382,6 +382,21 @@ struct reply_info* reply_info_copy(struct reply_info* rep,
int reply_info_alloc_rrset_keys(struct reply_info* rep,
struct alloc_cache* alloc, struct regional* region);
+/*
+ * Create a new reply_info based on 'rep'. The new info is based on
+ * the passed 'rep', but ignores any rrsets except for the first 'an_numrrsets'
+ * RRsets in the answer section. These answer rrsets are copied to the
+ * new info, up to 'copy_rrsets' rrsets (which must not be larger than
+ * 'an_numrrsets'). If an_numrrsets > copy_rrsets, the remaining rrsets array
+ * entries will be kept empty so the caller can fill them later. When rrsets
+ * are copied, they are shallow copied. The caller must ensure that the
+ * copied rrsets are valid throughout its lifetime and must provide appropriate
+ * mutex if it can be shared by multiple threads.
+ */
+struct reply_info *
+make_new_reply_info(const struct reply_info* rep, struct regional* region,
+ size_t an_numrrsets, size_t copy_rrsets);
+
/**
* Copy a parsed rrset into given key, decompressing and allocating rdata.
* @param pkt: packet for decompression
@@ -504,18 +519,6 @@ void log_query_info(enum verbosity_value v, const char* str,
struct query_info* qinf);
/**
- * Append edns option to edns data structure
- * @param edns: the edns data structure to append the edns option to.
- * @param region: region to allocate the new edns option.
- * @param code: the edns option's code.
- * @param len: the edns option's length.
- * @param data: the edns option's data.
- * @return false on failure.
- */
-int edns_opt_append(struct edns_data* edns, struct regional* region,
- uint16_t code, size_t len, uint8_t* data);
-
-/**
* Append edns option to edns option list
* @param list: the edns option list to append the edns option to.
* @param code: the edns option's code.
diff --git a/contrib/unbound/util/data/packed_rrset.h b/contrib/unbound/util/data/packed_rrset.h
index ff95c0af0e8d..e1feb22bb7f6 100644
--- a/contrib/unbound/util/data/packed_rrset.h
+++ b/contrib/unbound/util/data/packed_rrset.h
@@ -61,6 +61,13 @@ typedef uint64_t rrset_id_type;
* updated on encoding in a reply. This flag is not expected to be set in
* cached data. */
#define PACKED_RRSET_FIXEDTTL 0x80000000
+/** This rrset is from RPZ. It is not real, it is synthesized data to block
+ * access. The flag makes lookups, from cache in iterator, ignore the fake
+ * items and only use actual data. Eg. when the iterator looksup NS, CNAME,
+ * A and AAAA types, it then gets items without this flag that are the
+ * actual network. But messages with these records in it can be stored in
+ * the cache and retrieved for a reply. */
+#define PACKED_RRSET_RPZ 0x8
/** number of rrs and rrsets for integer overflow protection. More than
* this is not really possible (64K packet has much less RRs and RRsets) in
@@ -88,6 +95,7 @@ struct packed_rrset_key {
* o PACKED_RRSET_PARENT_SIDE
* o PACKED_RRSET_SOA_NEG
* o PACKED_RRSET_FIXEDTTL (not supposed to be cached)
+ * o PACKED_RRSET_RPZ
*/
uint32_t flags;
/** the rrset type in network format */
diff --git a/contrib/unbound/util/edns.c b/contrib/unbound/util/edns.c
index 664cadd53da9..e0819f1cd3b4 100644
--- a/contrib/unbound/util/edns.c
+++ b/contrib/unbound/util/edns.c
@@ -133,53 +133,3 @@ edns_string_addr_lookup(rbtree_type* tree, struct sockaddr_storage* addr,
return (struct edns_string_addr*)addr_tree_lookup(tree, addr, addrlen);
}
-static int edns_keepalive(struct edns_data* edns_out, struct edns_data* edns_in,
- struct comm_point* c, struct regional* region)
-{
- if(c->type == comm_udp)
- return 1;
-
- /* To respond with a Keepalive option, the client connection
- * must have received one message with a TCP Keepalive EDNS option,
- * and that option must have 0 length data. Subsequent messages
- * sent on that connection will have a TCP Keepalive option.
- */
- if(c->tcp_keepalive ||
- edns_opt_list_find(edns_in->opt_list, LDNS_EDNS_KEEPALIVE)) {
- int keepalive = c->tcp_timeout_msec / 100;
- uint8_t data[2];
- data[0] = (uint8_t)((keepalive >> 8) & 0xff);
- data[1] = (uint8_t)(keepalive & 0xff);
- if(!edns_opt_list_append(&edns_out->opt_list, LDNS_EDNS_KEEPALIVE,
- sizeof(data), data, region))
- return 0;
- c->tcp_keepalive = 1;
- }
- return 1;
-}
-
-int apply_edns_options(struct edns_data* edns_out, struct edns_data* edns_in,
- struct config_file* cfg, struct comm_point* c, struct regional* region)
-{
- if(cfg->do_tcp_keepalive &&
- !edns_keepalive(edns_out, edns_in, c, region))
- return 0;
-
- if (cfg->nsid && edns_opt_list_find(edns_in->opt_list, LDNS_EDNS_NSID)
- && !edns_opt_list_append(&edns_out->opt_list,
- LDNS_EDNS_NSID, cfg->nsid_len, cfg->nsid, region))
- return 0;
-
- if(!cfg->pad_responses || c->type != comm_tcp || !c->ssl
- || !edns_opt_list_find(edns_in->opt_list, LDNS_EDNS_PADDING)) {
- ; /* pass */
- }
-
- else if(!edns_opt_list_append(&edns_out->opt_list, LDNS_EDNS_PADDING
- , 0, NULL, region))
- return 0;
- else
- edns_out->padding_block_size = cfg->pad_responses_block_size;
-
- return 1;
-}
diff --git a/contrib/unbound/util/edns.h b/contrib/unbound/util/edns.h
index 11742eb5b723..d9ded0b84dc4 100644
--- a/contrib/unbound/util/edns.h
+++ b/contrib/unbound/util/edns.h
@@ -106,16 +106,4 @@ struct edns_string_addr*
edns_string_addr_lookup(rbtree_type* tree, struct sockaddr_storage* addr,
socklen_t addrlen);
-/**
- * Apply common EDNS options.
- *
- * @param edns_out: initialised edns information with outbound edns.
- * @param edns_in: initialised edns information with received edns.
- * @param cfg: configuration.
- * @param c: comm channel.
- * @param region: the region to allocate the edns options in.
- */
-int apply_edns_options(struct edns_data* edns_out, struct edns_data* edns_in,
- struct config_file* cfg, struct comm_point* c, struct regional* region);
-
#endif
diff --git a/contrib/unbound/util/fptr_wlist.c b/contrib/unbound/util/fptr_wlist.c
index de6dbd02a37d..f8dac65c59a0 100644
--- a/contrib/unbound/util/fptr_wlist.c
+++ b/contrib/unbound/util/fptr_wlist.c
@@ -335,7 +335,7 @@ int
fptr_whitelist_modenv_send_query(struct outbound_entry* (*fptr)(
struct query_info* qinfo, uint16_t flags, int dnssec, int want_dnssec,
int nocaps, struct sockaddr_storage* addr, socklen_t addrlen,
- uint8_t* zone, size_t zonelen, int ssl_upstream, char* tls_auth_name,
+ uint8_t* zone, size_t zonelen, int tcp_upstream, int ssl_upstream, char* tls_auth_name,
struct module_qstate* q))
{
if(fptr == &worker_send_query) return 1;
diff --git a/contrib/unbound/util/fptr_wlist.h b/contrib/unbound/util/fptr_wlist.h
index cd331febb070..a5470992550f 100644
--- a/contrib/unbound/util/fptr_wlist.h
+++ b/contrib/unbound/util/fptr_wlist.h
@@ -212,7 +212,7 @@ int fptr_whitelist_hash_markdelfunc(lruhash_markdelfunc_type fptr);
int fptr_whitelist_modenv_send_query(struct outbound_entry* (*fptr)(
struct query_info* qinfo, uint16_t flags, int dnssec, int want_dnssec,
int nocaps, struct sockaddr_storage* addr, socklen_t addrlen,
- uint8_t* zone, size_t zonelen, int ssl_upstream, char* tls_auth_name,
+ uint8_t* zone, size_t zonelen, int tcp_upstream, int ssl_upstream, char* tls_auth_name,
struct module_qstate* q));
/**
diff --git a/contrib/unbound/util/iana_ports.inc b/contrib/unbound/util/iana_ports.inc
index b93af015da6f..9183c3987292 100644
--- a/contrib/unbound/util/iana_ports.inc
+++ b/contrib/unbound/util/iana_ports.inc
@@ -2499,6 +2499,7 @@
2870,
2871,
2872,
+2873,
2874,
2875,
2876,
diff --git a/contrib/unbound/util/mini_event.c b/contrib/unbound/util/mini_event.c
index 661d88d2e6f6..c05dc668c676 100644
--- a/contrib/unbound/util/mini_event.c
+++ b/contrib/unbound/util/mini_event.c
@@ -337,6 +337,15 @@ int event_del(struct event* ev)
FD_CLR(FD_SET_T ev->ev_fd, &ev->ev_base->writes);
FD_CLR(FD_SET_T ev->ev_fd, &ev->ev_base->ready);
FD_CLR(FD_SET_T ev->ev_fd, &ev->ev_base->content);
+ if(ev->ev_fd == ev->ev_base->maxfd) {
+ int i = ev->ev_base->maxfd - 1;
+ for (; i > 3; i--) {
+ if (NULL != ev->ev_base->fds[i]) {
+ break;
+ }
+ }
+ ev->ev_base->maxfd = i;
+ }
}
ev->added = 0;
return 0;
diff --git a/contrib/unbound/util/module.h b/contrib/unbound/util/module.h
index 81a31a9cca46..c6b7e573ce00 100644
--- a/contrib/unbound/util/module.h
+++ b/contrib/unbound/util/module.h
@@ -354,10 +354,11 @@ struct module_env {
* @param addrlen: length of addr.
* @param zone: delegation point name.
* @param zonelen: length of zone name.
+ * @param tcp_upstream: use TCP for upstream queries.
* @param ssl_upstream: use SSL for upstream queries.
* @param tls_auth_name: if ssl_upstream, use this name with TLS
* authentication.
- * @param q: wich query state to reactivate upon return.
+ * @param q: which query state to reactivate upon return.
* @return: false on failure (memory or socket related). no query was
* sent. Or returns an outbound entry with qsent and qstate set.
* This outbound_entry will be used on later module invocations
@@ -366,7 +367,7 @@ struct module_env {
struct outbound_entry* (*send_query)(struct query_info* qinfo,
uint16_t flags, int dnssec, int want_dnssec, int nocaps,
struct sockaddr_storage* addr, socklen_t addrlen,
- uint8_t* zone, size_t zonelen, int ssl_upstream,
+ uint8_t* zone, size_t zonelen, int tcp_upstream, int ssl_upstream,
char* tls_auth_name, struct module_qstate* q);
/**
diff --git a/contrib/unbound/util/net_help.c b/contrib/unbound/util/net_help.c
index 06bc1f5dd7e6..d63fccd55ca2 100644
--- a/contrib/unbound/util/net_help.c
+++ b/contrib/unbound/util/net_help.c
@@ -38,6 +38,12 @@
*/
#include "config.h"
+#ifdef HAVE_SYS_TYPES_H
+# include <sys/types.h>
+#endif
+#ifdef HAVE_NET_IF_H
+#include <net/if.h>
+#endif
#include "util/net_help.h"
#include "util/log.h"
#include "util/data/dname.h"
@@ -266,7 +272,10 @@ ipstrtoaddr(const char* ip, int port, struct sockaddr_storage* addr,
return 0;
(void)strlcpy(buf, ip, sizeof(buf));
buf[s-ip]=0;
- sa->sin6_scope_id = (uint32_t)atoi(s+1);
+#ifdef HAVE_IF_NAMETOINDEX
+ if (!(sa->sin6_scope_id = if_nametoindex(s+1)))
+#endif /* HAVE_IF_NAMETOINDEX */
+ sa->sin6_scope_id = (uint32_t)atoi(s+1);
ip = buf;
}
if(inet_pton((int)sa->sin6_family, ip, &sa->sin6_addr) <= 0) {
@@ -881,6 +890,12 @@ log_cert(unsigned level, const char* str, void* cert)
BIO_write(bio, &nul, (int)sizeof(nul));
len = BIO_get_mem_data(bio, &pp);
if(len != 0 && pp) {
+ /* reduce size of cert printout */
+ char* s;
+ while((s=strstr(pp, " "))!=NULL)
+ memmove(s, s+1, strlen(s+1)+1);
+ while((s=strstr(pp, "\t\t"))!=NULL)
+ memmove(s, s+1, strlen(s+1)+1);
verbose(level, "%s: \n%s", str, pp);
}
BIO_free(bio);
@@ -945,9 +960,12 @@ listen_sslctx_setup(void* ctxt)
}
#endif
#if defined(SHA256_DIGEST_LENGTH) && defined(USE_ECDSA)
+ /* if we detect system-wide crypto policies, use those */
+ if (access( "/etc/crypto-policies/config", F_OK ) != 0 ) {
/* if we have sha256, set the cipher list to have no known vulns */
- if(!SSL_CTX_set_cipher_list(ctx, "TLS13-CHACHA20-POLY1305-SHA256:TLS13-AES-256-GCM-SHA384:TLS13-AES-128-GCM-SHA256:ECDHE-ECDSA-CHACHA20-POLY1305:ECDHE-RSA-CHACHA20-POLY1305:ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256"))
- log_crypto_err("could not set cipher list with SSL_CTX_set_cipher_list");
+ if(!SSL_CTX_set_cipher_list(ctx, "TLS13-CHACHA20-POLY1305-SHA256:TLS13-AES-256-GCM-SHA384:TLS13-AES-128-GCM-SHA256:ECDHE-ECDSA-CHACHA20-POLY1305:ECDHE-RSA-CHACHA20-POLY1305:ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256"))
+ log_crypto_err("could not set cipher list with SSL_CTX_set_cipher_list");
+ }
#endif
if((SSL_CTX_set_options(ctx, SSL_OP_CIPHER_SERVER_PREFERENCE) &
@@ -1172,6 +1190,7 @@ void* connect_sslctx_create(char* key, char* pem, char* verifypem, int wincert)
if((SSL_CTX_set_options(ctx, SSL_OP_NO_RENEGOTIATION) &
SSL_OP_NO_RENEGOTIATION) != SSL_OP_NO_RENEGOTIATION) {
log_crypto_err("could not set SSL_OP_NO_RENEGOTIATION");
+ SSL_CTX_free(ctx);
return 0;
}
#endif
diff --git a/contrib/unbound/util/netevent.c b/contrib/unbound/util/netevent.c
index 11c642a2bc38..595e5dc80516 100644
--- a/contrib/unbound/util/netevent.c
+++ b/contrib/unbound/util/netevent.c
@@ -300,6 +300,7 @@ udp_send_errno_needs_log(struct sockaddr* addr, socklen_t addrlen)
case ENETDOWN:
# endif
case EPERM:
+ case EACCES:
if(verbosity < VERB_ALGO)
return 0;
default:
@@ -817,6 +818,7 @@ setup_tcp_handler(struct comm_point* c, int fd, int cur, int max)
#endif
c->tcp_is_reading = 1;
c->tcp_byte_count = 0;
+ c->tcp_keepalive = 0;
/* if more than half the tcp handlers are in use, use a shorter
* timeout for this TCP connection, we need to make space for
* other connections to be able to get attention */
@@ -942,7 +944,16 @@ int comm_point_perform_accept(struct comm_point* c,
#ifdef USE_WINSOCK
static long win_bio_cb(BIO *b, int oper, const char* ATTR_UNUSED(argp),
- int ATTR_UNUSED(argi), long argl, long retvalue)
+#ifdef HAVE_BIO_SET_CALLBACK_EX
+ size_t ATTR_UNUSED(len),
+#endif
+ int ATTR_UNUSED(argi), long argl,
+#ifndef HAVE_BIO_SET_CALLBACK_EX
+ long retvalue
+#else
+ int retvalue, size_t* ATTR_UNUSED(processed)
+#endif
+ )
{
int wsa_err = WSAGetLastError(); /* store errcode before it is gone */
verbose(VERB_ALGO, "bio_cb %d, %s %s %s", oper,
@@ -972,9 +983,17 @@ comm_point_tcp_win_bio_cb(struct comm_point* c, void* thessl)
{
SSL* ssl = (SSL*)thessl;
/* set them both just in case, but usually they are the same BIO */
+#ifdef HAVE_BIO_SET_CALLBACK_EX
+ BIO_set_callback_ex(SSL_get_rbio(ssl), &win_bio_cb);
+#else
BIO_set_callback(SSL_get_rbio(ssl), &win_bio_cb);
+#endif
BIO_set_callback_arg(SSL_get_rbio(ssl), (char*)c->ev->ev);
+#ifdef HAVE_BIO_SET_CALLBACK_EX
+ BIO_set_callback_ex(SSL_get_wbio(ssl), &win_bio_cb);
+#else
BIO_set_callback(SSL_get_wbio(ssl), &win_bio_cb);
+#endif
BIO_set_callback_arg(SSL_get_wbio(ssl), (char*)c->ev->ev);
}
#endif
@@ -1036,6 +1055,7 @@ comm_point_tcp_accept_callback(int fd, short event, void* arg)
/* clear leftover flags from previous use, and then set the
* correct event base for the event structure for libevent */
ub_event_free(c_hdl->ev->ev);
+ c_hdl->ev->ev = NULL;
if((c_hdl->type == comm_tcp && c_hdl->tcp_req_info) ||
c_hdl->type == comm_local || c_hdl->type == comm_raw)
c_hdl->tcp_do_toggle_rw = 0;
@@ -1092,6 +1112,7 @@ comm_point_tcp_accept_callback(int fd, short event, void* arg)
/* grab the tcp handler buffers */
c->cur_tcp_count++;
c->tcp_free = c_hdl->tcp_free;
+ c_hdl->tcp_free = NULL;
if(!c->tcp_free) {
/* stop accepting incoming queries for now. */
comm_point_stop_listening(c);
@@ -1113,9 +1134,11 @@ reclaim_tcp_handler(struct comm_point* c)
}
comm_point_close(c);
if(c->tcp_parent) {
- c->tcp_parent->cur_tcp_count--;
- c->tcp_free = c->tcp_parent->tcp_free;
- c->tcp_parent->tcp_free = c;
+ if(c != c->tcp_parent->tcp_free) {
+ c->tcp_parent->cur_tcp_count--;
+ c->tcp_free = c->tcp_parent->tcp_free;
+ c->tcp_parent->tcp_free = c;
+ }
if(!c->tcp_free) {
/* re-enable listening on accept socket */
comm_point_start_listening(c->tcp_parent, -1, -1);
@@ -1862,13 +1885,22 @@ comm_point_tcp_handle_write(int fd, struct comm_point* c)
if(errno == EINTR || errno == EAGAIN)
return 1;
/* Not handling EISCONN here as shouldn't ever hit that case.*/
- if(errno != EPIPE && errno != 0 && verbosity < 2)
- return 0; /* silence lots of chatter in the logs */
- if(errno != EPIPE && errno != 0) {
+ if(errno != EPIPE
+#ifdef EOPNOTSUPP
+ /* if /proc/sys/net/ipv4/tcp_fastopen is
+ * disabled on Linux, sendmsg may return
+ * 'Operation not supported', if so
+ * fallthrough to ordinary connect. */
+ && errno != EOPNOTSUPP
+#endif
+ && errno != 0) {
+ if(verbosity < 2)
+ return 0; /* silence lots of chatter in the logs */
log_err_addr("tcp sendmsg", strerror(errno),
&c->repinfo.addr, c->repinfo.addrlen);
return 0;
}
+ verbose(VERB_ALGO, "tcp sendmsg for fastopen failed (with %s), try normal connect", strerror(errno));
/* fallthrough to nonFASTOPEN
* (MSG_FASTOPEN on Linux 3 produces EPIPE)
* we need to perform connect() */
@@ -2201,9 +2233,11 @@ reclaim_http_handler(struct comm_point* c)
}
comm_point_close(c);
if(c->tcp_parent) {
- c->tcp_parent->cur_tcp_count--;
- c->tcp_free = c->tcp_parent->tcp_free;
- c->tcp_parent->tcp_free = c;
+ if(c != c->tcp_parent->tcp_free) {
+ c->tcp_parent->cur_tcp_count--;
+ c->tcp_free = c->tcp_parent->tcp_free;
+ c->tcp_parent->tcp_free = c;
+ }
if(!c->tcp_free) {
/* re-enable listening on accept socket */
comm_point_start_listening(c->tcp_parent, -1, -1);
@@ -4140,6 +4174,10 @@ comm_point_start_listening(struct comm_point* c, int newfd, int msec)
c->timeout->tv_sec = msec/1000;
c->timeout->tv_usec = (msec%1000)*1000;
#endif /* S_SPLINT_S */
+ } else {
+ if(msec == 0 || !c->timeout) {
+ ub_event_del_bits(c->ev->ev, UB_EV_TIMEOUT);
+ }
}
if(c->type == comm_tcp || c->type == comm_http) {
ub_event_del_bits(c->ev->ev, UB_EV_READ|UB_EV_WRITE);
@@ -4164,6 +4202,7 @@ comm_point_start_listening(struct comm_point* c, int newfd, int msec)
}
if(ub_event_add(c->ev->ev, msec==0?NULL:c->timeout) != 0) {
log_err("event_add failed. in cpsl.");
+ return;
}
c->event_added = 1;
}
@@ -4177,11 +4216,15 @@ void comm_point_listen_for_rw(struct comm_point* c, int rd, int wr)
}
c->event_added = 0;
}
+ if(!c->timeout) {
+ ub_event_del_bits(c->ev->ev, UB_EV_TIMEOUT);
+ }
ub_event_del_bits(c->ev->ev, UB_EV_READ|UB_EV_WRITE);
if(rd) ub_event_add_bits(c->ev->ev, UB_EV_READ);
if(wr) ub_event_add_bits(c->ev->ev, UB_EV_WRITE);
if(ub_event_add(c->ev->ev, c->timeout) != 0) {
log_err("event_add failed. in cplf.");
+ return;
}
c->event_added = 1;
}
diff --git a/contrib/unbound/util/netevent.h b/contrib/unbound/util/netevent.h
index c79f99b3eb6d..9f4d28ba9f8f 100644
--- a/contrib/unbound/util/netevent.h
+++ b/contrib/unbound/util/netevent.h
@@ -743,7 +743,7 @@ struct comm_signal* comm_signal_create(struct comm_base* base,
void (*callback)(int, void*), void* cb_arg);
/**
- * Bind signal struct to catch a signal. A signle comm_signal can be bound
+ * Bind signal struct to catch a signal. A single comm_signal can be bound
* to multiple signals, calling comm_signal_bind multiple times.
* @param comsig: the communication point, with callback information.
* @param sig: signal number.
diff --git a/contrib/unbound/util/regional.c b/contrib/unbound/util/regional.c
index bd67ecf50af3..93e911c5ec1a 100644
--- a/contrib/unbound/util/regional.c
+++ b/contrib/unbound/util/regional.c
@@ -103,6 +103,8 @@ regional_create_custom_large_object(size_t size, size_t large_object_size)
struct regional*
regional_create_custom(size_t size)
{
+ if(size < sizeof(struct regional))
+ size = sizeof(struct regional);
return regional_create_custom_large_object(size,
REGIONAL_LARGE_OBJECT_SIZE);
}
diff --git a/contrib/unbound/util/shm_side/shm_main.c b/contrib/unbound/util/shm_side/shm_main.c
index 51039abf3ed8..6fd1f5ea638c 100644
--- a/contrib/unbound/util/shm_side/shm_main.c
+++ b/contrib/unbound/util/shm_side/shm_main.c
@@ -281,7 +281,7 @@ void shm_main_run(struct worker *worker)
shm_stat->mem.subnet = 0;
#ifdef CLIENT_SUBNET
shm_stat->mem.subnet = (long long)mod_get_mem(&worker->env,
- "subnet");
+ "subnetcache");
#endif
/* ipsecmod mem value is available in shm, also when not enabled,
* to make the struct easier to memmap by other applications,
diff --git a/contrib/unbound/util/tube.c b/contrib/unbound/util/tube.c
index dc6e3c2e7f78..40556e72020b 100644
--- a/contrib/unbound/util/tube.c
+++ b/contrib/unbound/util/tube.c
@@ -363,7 +363,11 @@ int tube_read_msg(struct tube* tube, uint8_t** buf, uint32_t* len,
}
d += r;
}
- log_assert(*len < 65536*2);
+ if (*len >= 65536*2) {
+ log_err("tube msg length %u is too big", (unsigned)*len);
+ (void)fd_set_nonblock(fd);
+ return 0;
+ }
*buf = (uint8_t*)malloc(*len);
if(!*buf) {
log_err("tube read out of memory");
diff --git a/contrib/unbound/util/ub_event.c b/contrib/unbound/util/ub_event.c
index 68f633bb0ef2..8cd87ec4e1d4 100644
--- a/contrib/unbound/util/ub_event.c
+++ b/contrib/unbound/util/ub_event.c
@@ -1,5 +1,5 @@
/*
- * util/ub_event.c - directly call libevent (compatability) functions
+ * util/ub_event.c - directly call libevent (compatibility) functions
*
* Copyright (c) 2007, NLnet Labs. All rights reserved.
*
diff --git a/contrib/unbound/validator/autotrust.c b/contrib/unbound/validator/autotrust.c
index 9643a3ddb38b..55e82c176dae 100644
--- a/contrib/unbound/validator/autotrust.c
+++ b/contrib/unbound/validator/autotrust.c
@@ -2377,7 +2377,9 @@ probe_anchor(struct module_env* env, struct trust_anchor* tp)
edns.ext_rcode = 0;
edns.edns_version = 0;
edns.bits = EDNS_DO;
- edns.opt_list = NULL;
+ edns.opt_list_in = NULL;
+ edns.opt_list_out = NULL;
+ edns.opt_list_inplace_cb_out = NULL;
edns.padding_block_size = 0;
if(sldns_buffer_capacity(buf) < 65535)
edns.udp_size = (uint16_t)sldns_buffer_capacity(buf);
diff --git a/contrib/unbound/validator/validator.c b/contrib/unbound/validator/validator.c
index d4d48d956895..e6307284fb0e 100644
--- a/contrib/unbound/validator/validator.c
+++ b/contrib/unbound/validator/validator.c
@@ -140,7 +140,7 @@ val_apply_cfg(struct module_env* env, struct val_env* val_env,
val_env->max_restart = cfg->val_max_restart;
c = cfg_count_numbers(cfg->val_nsec3_key_iterations);
if(c < 1 || (c&1)) {
- log_err("validator: unparseable or odd nsec3 key "
+ log_err("validator: unparsable or odd nsec3 key "
"iterations: %s", cfg->val_nsec3_key_iterations);
return 0;
}
@@ -484,7 +484,7 @@ generate_keytag_query(struct module_qstate* qstate, int id,
return 0;
}
- /* Not interrested in subquery response. Restore the ext_state,
+ /* Not interested in subquery response. Restore the ext_state,
* that might be changed by generate_request() */
qstate->ext_state[id] = ext_state;
diff --git a/contrib/unbound/validator/validator.h b/contrib/unbound/validator/validator.h
index a928e10a65d8..a97eab25bc4a 100644
--- a/contrib/unbound/validator/validator.h
+++ b/contrib/unbound/validator/validator.h
@@ -68,7 +68,7 @@ struct config_strlist;
#define SENTINEL_IS "root-key-sentinel-is-ta-"
/** Root key sentinel is not ta preamble */
#define SENTINEL_NOT "root-key-sentinel-not-ta-"
-/** Root key sentinal keytag length */
+/** Root key sentinel keytag length */
#define SENTINEL_KEYTAG_LEN 5
/**