mirror of
https://github.com/NLnetLabs/unbound.git
synced 2026-10-21 15:51:32 +02:00
Compare commits
138
Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
22a36aa530 | ||
|
|
1ca8678523 | ||
|
|
2478ca4c44 | ||
|
|
81d192387d | ||
|
|
37776636b6 | ||
|
|
1d0d27513a | ||
|
|
254492739d | ||
|
|
6f2f265616 | ||
|
|
0bb522715e | ||
|
|
2bd5309d20 | ||
|
|
d1dd5aa905 | ||
|
|
1f05433d54 | ||
|
|
7d91d6345f | ||
|
|
3fce3be652 | ||
|
|
f981776b07 | ||
|
|
a5cd943877 | ||
|
|
efad833e28 | ||
|
|
29bd80e53c | ||
|
|
2f2d9229e7 | ||
|
|
3d429e7fed | ||
|
|
ed5b3b23b3 | ||
|
|
970e7db1a0 | ||
|
|
ed954b6c18 | ||
|
|
024730aca7 | ||
|
|
660bfddeba | ||
|
|
3ed72c7681 | ||
|
|
440d58045e | ||
|
|
e3a0ce98c4 | ||
|
|
d498d8279f | ||
|
|
c5de558e04 | ||
|
|
be5d1e967a | ||
|
|
6cd9955385 | ||
|
|
aa7634afeb | ||
|
|
854ef1c2a4 | ||
|
|
ea96dcf166 | ||
|
|
d648eac68d | ||
|
|
0c4b782c8e | ||
|
|
8f022e1aa5 | ||
|
|
7380fd7107 | ||
|
|
456c85544b | ||
|
|
276a2db8af | ||
|
|
6180f1b6d0 | ||
|
|
0acb0ab631 | ||
|
|
cd0a585fbe | ||
|
|
d1ea227e94 | ||
|
|
18d8676e9c | ||
|
|
7c624d1dcd | ||
|
|
e23010c18e | ||
|
|
ddcbc291fe | ||
|
|
a119b1abc6 | ||
|
|
f62214e714 | ||
|
|
3d1aaae57a | ||
|
|
614dcbf675 | ||
|
|
add0065c43 | ||
|
|
3d53f08bd8 | ||
|
|
0dcd4cd2e8 | ||
|
|
b449d6f713 | ||
|
|
6932ae18f5 | ||
|
|
e2537840ba | ||
|
|
b425be8e10 | ||
|
|
bb408e503c | ||
|
|
8942d11bb3 | ||
|
|
cb027ae649 | ||
|
|
eafb027166 | ||
|
|
40d36cda61 | ||
|
|
8cf2202c52 | ||
|
|
f6fff9efcb | ||
|
|
97c001f9dd | ||
|
|
1e12bef540 | ||
|
|
b49f452f0a | ||
|
|
8820254637 | ||
|
|
5483a73856 | ||
|
|
0e2470450c | ||
|
|
65814ad6f3 | ||
|
|
97d6cc3643 | ||
|
|
e79365ec61 | ||
|
|
a7fc80d8c5 | ||
|
|
5d89e0c2a7 | ||
|
|
b45c8b4b53 | ||
|
|
a6586ced92 | ||
|
|
3ad9b6aade | ||
|
|
5ccee67af2 | ||
|
|
b8577a9c04 | ||
|
|
18d9a5519e | ||
|
|
2df646e05f | ||
|
|
bdfa4d4c5d | ||
|
|
bd210d124b | ||
|
|
11900cc2b0 | ||
|
|
c04a5efb07 | ||
|
|
1060760650 | ||
|
|
f251a1157b | ||
|
|
292cf6526b | ||
|
|
ac935b9144 | ||
|
|
9dd370ba04 | ||
|
|
a6ccb2f74d | ||
|
|
32ff948a5b | ||
|
|
2ec2afd6b0 | ||
|
|
7fb79b0677 | ||
|
|
48d0aea60a | ||
|
|
17bbcac979 | ||
|
|
fd8ebbb19c | ||
|
|
2adbbea365 | ||
|
|
8ee0bca833 | ||
|
|
c58e6add2b | ||
|
|
156c00a727 | ||
|
|
d753f95956 | ||
|
|
93a56205cf | ||
|
|
709f622658 | ||
|
|
307fc6f062 | ||
|
|
8b33c5d7ff | ||
|
|
36bd52afb9 | ||
|
|
b7d13ff12b | ||
|
|
bdfcfb861f | ||
|
|
b444deffd2 | ||
|
|
ff28b7e5cf | ||
|
|
79b84bbc91 | ||
|
|
cbfc3b0342 | ||
|
|
61d6c0e766 | ||
|
|
b4daa2d0fa | ||
|
|
425b701fb9 | ||
|
|
0a5cde80f1 | ||
|
|
58ede90fdb | ||
|
|
55ae8da032 | ||
|
|
6bd86df72e | ||
|
|
0efd3605cc | ||
|
|
a2f2f53ef9 | ||
|
|
b5a03093f6 | ||
|
|
8eba898135 | ||
|
|
56f66de89f | ||
|
|
2fbaee2255 | ||
|
|
a122490461 | ||
|
|
7826b4f306 | ||
|
|
380994219f | ||
|
|
153accb8de | ||
|
|
7bb1c62263 | ||
|
|
1578b6e180 | ||
|
|
d4999d418c | ||
|
|
7994365385 |
-380
@@ -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
|
||||
@@ -0,0 +1,54 @@
|
||||
# Contributing to Unbound
|
||||
|
||||
This document offers guidelines on how to best contribute to Unbound, whether
|
||||
it being new features or correcting flaws or bugs.
|
||||
|
||||
## Code of Conduct
|
||||
|
||||
This project and everyone participating in it is governed by the [NLnet Labs
|
||||
Code of Conduct](https://www.nlnetlabs.nl/conduct/).
|
||||
By participating, you are expected to uphold this code.
|
||||
|
||||
## LLM Policy
|
||||
|
||||
Before contributing to this project, please be aware of the [NLnet Labs LLM Policy](https://www.nlnetlabs.nl/llm-policy).
|
||||
In a nutshell: we do not accept any LLM-generated contributions to
|
||||
code or documentation.
|
||||
|
||||
## Join the Community
|
||||
|
||||
We invite you to join the [NLnet Labs Commununity
|
||||
Forum](https://community.nlnetlabs.nl/) where Unbound has its own category.
|
||||
Please don't open a GitHub issue for a question.
|
||||
Instead, follow the discussion on the forum and ask questions there before you
|
||||
start sending patches.
|
||||
We prefer public discussions over private ones, so everyone in the community
|
||||
can participate and learn.
|
||||
|
||||
## License and copyright
|
||||
|
||||
When contributing with code, you agree to put your changes and new code under
|
||||
the same license Unbound is already using.
|
||||
When changing existing source code, do not alter the copyright of the original
|
||||
file(s).
|
||||
The copyright will still be owned by the original creator(s) or those who have
|
||||
been assigned copyright by the original author(s).
|
||||
|
||||
By submitting a patch to Unbound, you are assumed to have the right to the code
|
||||
and to be allowed by your employer or whatever to hand over that patch/code
|
||||
to us.
|
||||
We will credit you for your changes as far as possible, to give credit but also
|
||||
to keep a trace back to who made what changes.
|
||||
|
||||
## Sharing Your Changes
|
||||
|
||||
We would like you to submit a [pull request on
|
||||
GitHub](https://github.com/NLnetLabs/Unbound/pulls).
|
||||
Please note that you can create a draft pull request to indicate that you're
|
||||
still working on something but still share it with the maintainers to get some
|
||||
early feedback.
|
||||
|
||||
Once final, your change will be reviewed and discussed on GitHub.
|
||||
You will be expected to correct flaws pointed out and update accordingly.
|
||||
As a submitter of a change, you are the owner of that change until it has been
|
||||
merged.
|
||||
+4
-2
@@ -125,7 +125,7 @@ services/localzone.c services/mesh.c services/modstack.c services/view.c \
|
||||
services/rpz.c util/rfc_1982.c \
|
||||
services/outbound_list.c services/outside_network.c util/alloc.c \
|
||||
util/config_file.c util/configlexer.c util/configparser.c \
|
||||
util/shm_side/shm_main.c services/authzone.c \
|
||||
util/shm_side/shm_main.c services/authzone.c services/authload.c \
|
||||
util/fptr_wlist.c util/locks.c util/log.c util/mini_event.c util/module.c \
|
||||
util/netevent.c util/net_help.c util/random.c util/rbtree.c util/regional.c \
|
||||
util/rtt.c util/siphash.c util/edns.c util/storage/dnstree.c util/storage/lookup3.c \
|
||||
@@ -152,7 +152,8 @@ autotrust.lo val_anchor.lo rpz.lo rfc_1982.lo proxy_protocol.lo \
|
||||
validator.lo val_kcache.lo val_kentry.lo val_neg.lo val_nsec3.lo val_nsec.lo \
|
||||
val_secalgo.lo val_sigcrypt.lo val_utils.lo dns64.lo $(CACHEDB_OBJ) authzone.lo \
|
||||
$(SUBNET_OBJ) $(PYTHONMOD_OBJ) $(CHECKLOCK_OBJ) $(DNSTAP_OBJ) $(DNSCRYPT_OBJ) \
|
||||
$(IPSECMOD_OBJ) $(IPSET_OBJ) $(DYNLIBMOD_OBJ) respip.lo timeval_func.lo
|
||||
$(IPSECMOD_OBJ) $(IPSET_OBJ) $(DYNLIBMOD_OBJ) respip.lo timeval_func.lo \
|
||||
authload.lo
|
||||
COMMON_OBJ_WITHOUT_UB_EVENT=$(COMMON_OBJ_WITHOUT_NETCALL) netevent.lo listen_dnsport.lo \
|
||||
outside_network.lo
|
||||
COMMON_OBJ=$(COMMON_OBJ_WITHOUT_UB_EVENT) ub_event.lo
|
||||
@@ -721,6 +722,7 @@ depend:
|
||||
ipset.lo ipset.o: $(srcdir)/ipset/ipset.c
|
||||
doqclient.lo doqclient.o: $(srcdir)/testcode/doqclient.c
|
||||
unitdoq.lo unitdoq.o: $(srcdir)/testcode/unitdoq.c
|
||||
authload.lo authload.o: $(srcdir)/services/authload.c
|
||||
|
||||
# Dependencies
|
||||
dns.lo dns.o: $(srcdir)/services/cache/dns.c config.h $(srcdir)/iterator/iter_delegpt.h $(srcdir)/util/log.h \
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
#! /bin/sh
|
||||
# Guess values for system-dependent variables and create Makefiles.
|
||||
# Generated by GNU Autoconf 2.71 for unbound 1.26.2.
|
||||
# Generated by GNU Autoconf 2.71 for unbound 1.26.3.
|
||||
#
|
||||
# Report bugs to <unbound-bugs@nlnetlabs.nl or https://github.com/NLnetLabs/unbound/issues>.
|
||||
#
|
||||
@@ -622,8 +622,8 @@ MAKEFLAGS=
|
||||
# Identity of this package.
|
||||
PACKAGE_NAME='unbound'
|
||||
PACKAGE_TARNAME='unbound'
|
||||
PACKAGE_VERSION='1.26.2'
|
||||
PACKAGE_STRING='unbound 1.26.2'
|
||||
PACKAGE_VERSION='1.26.3'
|
||||
PACKAGE_STRING='unbound 1.26.3'
|
||||
PACKAGE_BUGREPORT='unbound-bugs@nlnetlabs.nl or https://github.com/NLnetLabs/unbound/issues'
|
||||
PACKAGE_URL=''
|
||||
|
||||
@@ -1513,7 +1513,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.26.2 to adapt to many kinds of systems.
|
||||
\`configure' configures unbound 1.26.3 to adapt to many kinds of systems.
|
||||
|
||||
Usage: $0 [OPTION]... [VAR=VALUE]...
|
||||
|
||||
@@ -1579,7 +1579,7 @@ fi
|
||||
|
||||
if test -n "$ac_init_help"; then
|
||||
case $ac_init_help in
|
||||
short | recursive ) echo "Configuration of unbound 1.26.2:";;
|
||||
short | recursive ) echo "Configuration of unbound 1.26.3:";;
|
||||
esac
|
||||
cat <<\_ACEOF
|
||||
|
||||
@@ -1832,7 +1832,7 @@ fi
|
||||
test -n "$ac_init_help" && exit $ac_status
|
||||
if $ac_init_version; then
|
||||
cat <<\_ACEOF
|
||||
unbound configure 1.26.2
|
||||
unbound configure 1.26.3
|
||||
generated by GNU Autoconf 2.71
|
||||
|
||||
Copyright (C) 2021 Free Software Foundation, Inc.
|
||||
@@ -2489,7 +2489,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.26.2, which was
|
||||
It was created by unbound $as_me 1.26.3, which was
|
||||
generated by GNU Autoconf 2.71. Invocation command line was
|
||||
|
||||
$ $0$ac_configure_args_raw
|
||||
@@ -3253,11 +3253,11 @@ UNBOUND_VERSION_MAJOR=1
|
||||
|
||||
UNBOUND_VERSION_MINOR=26
|
||||
|
||||
UNBOUND_VERSION_MICRO=2
|
||||
UNBOUND_VERSION_MICRO=3
|
||||
|
||||
|
||||
LIBUNBOUND_CURRENT=9
|
||||
LIBUNBOUND_REVISION=41
|
||||
LIBUNBOUND_REVISION=42
|
||||
LIBUNBOUND_AGE=1
|
||||
# 1.0.0 had 0:12:0
|
||||
# 1.0.1 had 0:13:0
|
||||
@@ -3366,6 +3366,7 @@ LIBUNBOUND_AGE=1
|
||||
# 1.26.0 had 9:39:1
|
||||
# 1.26.1 had 9:40:1
|
||||
# 1.26.2 had 9:41:1
|
||||
# 1.26.3 had 9:42:1
|
||||
|
||||
# Current -- the number of the binary API that we're implementing
|
||||
# Revision -- which iteration of the implementation of the binary
|
||||
@@ -25713,7 +25714,7 @@ printf "%s\n" "#define MAXSYSLOGMSGLEN 10240" >>confdefs.h
|
||||
|
||||
|
||||
|
||||
version=1.26.2
|
||||
version=1.26.3
|
||||
|
||||
{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for build time" >&5
|
||||
printf %s "checking for build time... " >&6; }
|
||||
@@ -26243,7 +26244,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.26.2, which was
|
||||
This file was extended by unbound $as_me 1.26.3, which was
|
||||
generated by GNU Autoconf 2.71. Invocation command line was
|
||||
|
||||
CONFIG_FILES = $CONFIG_FILES
|
||||
@@ -26311,7 +26312,7 @@ ac_cs_config_escaped=`printf "%s\n" "$ac_cs_config" | sed "s/^ //; s/'/'\\\\\\\\
|
||||
cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1
|
||||
ac_cs_config='$ac_cs_config_escaped'
|
||||
ac_cs_version="\\
|
||||
unbound config.status 1.26.2
|
||||
unbound config.status 1.26.3
|
||||
configured by $0, generated by GNU Autoconf 2.71,
|
||||
with options \\"\$ac_cs_config\\"
|
||||
|
||||
|
||||
+3
-2
@@ -12,14 +12,14 @@ sinclude(dnscrypt/dnscrypt.m4)
|
||||
# must be numbers. ac_defun because of later processing
|
||||
m4_define([VERSION_MAJOR],[1])
|
||||
m4_define([VERSION_MINOR],[26])
|
||||
m4_define([VERSION_MICRO],[2])
|
||||
m4_define([VERSION_MICRO],[3])
|
||||
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=41
|
||||
LIBUNBOUND_REVISION=42
|
||||
LIBUNBOUND_AGE=1
|
||||
# 1.0.0 had 0:12:0
|
||||
# 1.0.1 had 0:13:0
|
||||
@@ -128,6 +128,7 @@ LIBUNBOUND_AGE=1
|
||||
# 1.26.0 had 9:39:1
|
||||
# 1.26.1 had 9:40:1
|
||||
# 1.26.2 had 9:41:1
|
||||
# 1.26.3 had 9:42:1
|
||||
|
||||
# Current -- the number of the binary API that we're implementing
|
||||
# Revision -- which iteration of the implementation of the binary
|
||||
|
||||
+1
-1
@@ -554,7 +554,7 @@ move_into_cache(struct ub_packed_rrset_key* k,
|
||||
|
||||
ref.key = ak;
|
||||
ref.id = ak->id;
|
||||
(void)rrset_cache_update(worker->env.rrset_cache, &ref,
|
||||
rrset_cache_update_unlock(worker->env.rrset_cache, &ref,
|
||||
worker->alloc, *worker->env.now);
|
||||
|
||||
return 1;
|
||||
|
||||
+16
-1
@@ -86,6 +86,7 @@
|
||||
#include "services/view.h"
|
||||
#include "services/modstack.h"
|
||||
#include "services/authzone.h"
|
||||
#include "services/authload.h"
|
||||
#include "util/module.h"
|
||||
#include "util/random.h"
|
||||
#include "util/tube.h"
|
||||
@@ -590,6 +591,17 @@ daemon_init(void)
|
||||
free(daemon);
|
||||
return NULL;
|
||||
}
|
||||
if(!(daemon->auth_load_info = auth_load_info_create())) {
|
||||
edns_strings_delete(daemon->env->edns_strings);
|
||||
auth_zones_delete(daemon->env->auth_zones);
|
||||
acl_list_delete(daemon->acl_interface);
|
||||
acl_list_delete(daemon->acl);
|
||||
tcl_list_delete(daemon->tcl);
|
||||
edns_known_options_delete(daemon->env);
|
||||
free(daemon->env);
|
||||
free(daemon);
|
||||
return NULL;
|
||||
}
|
||||
return daemon;
|
||||
}
|
||||
|
||||
@@ -1077,7 +1089,7 @@ daemon_fork(struct daemon* daemon)
|
||||
daemon_setup_modules(daemon);
|
||||
|
||||
/* read auth zonefiles */
|
||||
if(!auth_zones_apply_cfg(daemon->env->auth_zones, daemon->cfg, 1,
|
||||
if(!auth_zones_apply_cfg(daemon->env->auth_zones, daemon->cfg, 1, 1,
|
||||
&daemon->use_rpz, daemon->env, &daemon->mods))
|
||||
fatal_exit("auth_zones could not be setup");
|
||||
|
||||
@@ -1164,6 +1176,7 @@ daemon_fork(struct daemon* daemon)
|
||||
|
||||
/* we exited! a signal happened! Stop other threads */
|
||||
daemon_stop_others(daemon);
|
||||
auth_load_stop_threads(daemon);
|
||||
|
||||
/* Shutdown SHM */
|
||||
shm_main_shutdown(daemon);
|
||||
@@ -1204,6 +1217,7 @@ daemon_cleanup(struct daemon* daemon)
|
||||
daemon->env->views = NULL;
|
||||
if(daemon->env->auth_zones)
|
||||
auth_zones_cleanup(daemon->env->auth_zones);
|
||||
auth_load_info_cleanup(daemon->auth_load_info);
|
||||
/* key cache is cleared by module deinit during next daemon_fork() */
|
||||
daemon_remote_clear(daemon->rc);
|
||||
if(daemon->fast_reload_thread)
|
||||
@@ -1262,6 +1276,7 @@ daemon_delete(struct daemon* daemon)
|
||||
edns_strings_delete(daemon->env->edns_strings);
|
||||
auth_zones_delete(daemon->env->auth_zones);
|
||||
}
|
||||
auth_load_info_delete(daemon->auth_load_info);
|
||||
ub_randfree(daemon->rand);
|
||||
alloc_clear(&daemon->superalloc);
|
||||
acl_list_delete(daemon->acl);
|
||||
|
||||
@@ -62,6 +62,7 @@ struct doq_table;
|
||||
struct cookie_secrets;
|
||||
struct fast_reload_thread;
|
||||
struct fast_reload_printq;
|
||||
struct auth_load_general_info;
|
||||
struct shared_ports;
|
||||
|
||||
#include "dnstap/dnstap_config.h"
|
||||
@@ -191,6 +192,8 @@ struct daemon {
|
||||
int fast_reload_tcl_has_changes;
|
||||
/** config file name */
|
||||
char* cfgfile;
|
||||
/** Auth load threads, the number of active threads. */
|
||||
struct auth_load_general_info* auth_load_info;
|
||||
};
|
||||
|
||||
/**
|
||||
|
||||
+35
-373
@@ -73,6 +73,7 @@
|
||||
#include "services/mesh.h"
|
||||
#include "services/localzone.h"
|
||||
#include "services/authzone.h"
|
||||
#include "services/authload.h"
|
||||
#include "services/rpz.h"
|
||||
#include "util/storage/slabhash.h"
|
||||
#include "util/fptr_wlist.h"
|
||||
@@ -115,9 +116,6 @@
|
||||
#ifdef HAVE_NETDB_H
|
||||
#include <netdb.h>
|
||||
#endif
|
||||
#ifdef HAVE_POLL_H
|
||||
#include <poll.h>
|
||||
#endif
|
||||
|
||||
/* just for portability */
|
||||
#ifdef SQ
|
||||
@@ -2681,7 +2679,7 @@ static int
|
||||
ssl_print_name_dp(RES* ssl, const char* str, uint8_t* nm, uint16_t dclass,
|
||||
struct delegpt* dp)
|
||||
{
|
||||
char buf[LDNS_MAX_DOMAINLEN];
|
||||
char buf[LDNS_MAX_DOMAINLEN], portstr[128], tls_auth_name[256];
|
||||
struct delegpt_ns* ns;
|
||||
struct delegpt_addr* a;
|
||||
int f = 0;
|
||||
@@ -2696,13 +2694,32 @@ ssl_print_name_dp(RES* ssl, const char* str, uint8_t* nm, uint16_t dclass,
|
||||
}
|
||||
for(ns = dp->nslist; ns; ns = ns->next) {
|
||||
dname_str(ns->name, buf);
|
||||
if(!ssl_printf(ssl, "%s%s", (f?" ":""), buf))
|
||||
if(ns->port != UNBOUND_DNS_PORT)
|
||||
snprintf(portstr, sizeof(portstr), "@%d", ns->port);
|
||||
else portstr[0]=0;
|
||||
if(ns->tls_auth_name)
|
||||
snprintf(tls_auth_name, sizeof(tls_auth_name), "#%s",
|
||||
ns->tls_auth_name);
|
||||
else tls_auth_name[0]=0;
|
||||
if(!ssl_printf(ssl, "%s%s%s%s", (f?" ":""), buf, portstr,
|
||||
tls_auth_name))
|
||||
return 0;
|
||||
f = 1;
|
||||
}
|
||||
for(a = dp->target_list; a; a = a->next_target) {
|
||||
int port = (unsigned)((a->addr.ss_family == AF_INET) ?
|
||||
ntohs(((struct sockaddr_in*)&a->addr)->sin_port) :
|
||||
ntohs(((struct sockaddr_in6*)&a->addr)->sin6_port));
|
||||
addr_to_str(&a->addr, a->addrlen, buf, sizeof(buf));
|
||||
if(!ssl_printf(ssl, "%s%s", (f?" ":""), buf))
|
||||
if(port != UNBOUND_DNS_PORT)
|
||||
snprintf(portstr, sizeof(portstr), "@%d", port);
|
||||
else portstr[0]=0;
|
||||
if(a->tls_auth_name)
|
||||
snprintf(tls_auth_name, sizeof(tls_auth_name), "#%s",
|
||||
a->tls_auth_name);
|
||||
else tls_auth_name[0]=0;
|
||||
if(!ssl_printf(ssl, "%s%s%s%s", (f?" ":""), buf, portstr,
|
||||
tls_auth_name))
|
||||
return 0;
|
||||
f = 1;
|
||||
}
|
||||
@@ -4447,92 +4464,6 @@ int remote_control_callback(struct comm_point* c, void* arg, int err,
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* This routine polls a socket for readiness.
|
||||
* @param fd: file descriptor, -1 uses no fd for a timer only.
|
||||
* @param timeout: time in msec to wait. 0 means nonblocking test,
|
||||
* -1 waits blocking for events.
|
||||
* @param pollin: check for input event.
|
||||
* @param pollout: check for output event.
|
||||
* @param event: output variable, set to true if the event happens.
|
||||
* It is false if there was an error or timeout.
|
||||
* @return false is system call failure, also logged.
|
||||
*/
|
||||
static int
|
||||
sock_poll_timeout(int fd, int timeout, int pollin, int pollout, int* event)
|
||||
{
|
||||
int loopcount = 0;
|
||||
/* Loop if the system call returns an errno to do so, like EINTR. */
|
||||
log_assert(pollin || pollout);
|
||||
while(1) {
|
||||
struct pollfd p, *fds;
|
||||
int nfds, ret;
|
||||
if(++loopcount > IPC_LOOP_MAX) {
|
||||
log_err("sock_poll_timeout: loop");
|
||||
if(event)
|
||||
*event = 0;
|
||||
return 0;
|
||||
}
|
||||
if(fd == -1) {
|
||||
fds = NULL;
|
||||
nfds = 0;
|
||||
} else {
|
||||
fds = &p;
|
||||
nfds = 1;
|
||||
memset(&p, 0, sizeof(p));
|
||||
p.fd = fd;
|
||||
#ifndef USE_WINSOCK
|
||||
p.events = POLLERR
|
||||
| POLLHUP
|
||||
;
|
||||
#endif
|
||||
if(pollin)
|
||||
p.events |= POLLIN;
|
||||
if(pollout)
|
||||
p.events |= POLLOUT;
|
||||
}
|
||||
#ifndef USE_WINSOCK
|
||||
ret = poll(fds, nfds, timeout);
|
||||
#else
|
||||
if(fds == NULL) {
|
||||
Sleep(timeout);
|
||||
ret = 0;
|
||||
} else {
|
||||
ret = WSAPoll(fds, nfds, timeout);
|
||||
}
|
||||
#endif
|
||||
if(ret == -1) {
|
||||
#ifndef USE_WINSOCK
|
||||
if(
|
||||
errno == EINTR || errno == EAGAIN
|
||||
# ifdef EWOULDBLOCK
|
||||
|| errno == EWOULDBLOCK
|
||||
# endif
|
||||
) continue; /* Try again. */
|
||||
#endif
|
||||
/* For WSAPoll we only get errors here:
|
||||
* o WSAENETDOWN
|
||||
* o WSAEFAULT
|
||||
* o WSAEINVAL
|
||||
* o WSAENOBUFS
|
||||
*/
|
||||
log_err("poll: %s", sock_strerror(errno));
|
||||
if(event)
|
||||
*event = 0;
|
||||
return 0;
|
||||
} else if(ret == 0) {
|
||||
/* Timeout */
|
||||
if(event)
|
||||
*event = 0;
|
||||
return 1;
|
||||
}
|
||||
break;
|
||||
}
|
||||
if(event)
|
||||
*event = 1;
|
||||
return 1;
|
||||
}
|
||||
|
||||
/** fast reload convert fast reload notification status to string */
|
||||
static const char*
|
||||
fr_notification_to_string(enum fast_reload_notification status)
|
||||
@@ -5961,7 +5892,7 @@ fr_construct_from_config(struct fast_reload_thread* fr,
|
||||
fr_construct_clear(ct);
|
||||
return 0;
|
||||
}
|
||||
if(!auth_zones_apply_cfg(ct->auth_zones, newcfg, 1, &ct->use_rpz,
|
||||
if(!auth_zones_apply_cfg(ct->auth_zones, newcfg, 1, 1, &ct->use_rpz,
|
||||
fr->worker->daemon->env, &fr->worker->daemon->mods)) {
|
||||
fr_construct_clear(ct);
|
||||
return 0;
|
||||
@@ -6346,6 +6277,7 @@ fr_atomic_copy_cfg(struct config_file* oldcfg, struct config_file* cfg,
|
||||
COPY_VAR_ptr(acls);
|
||||
COPY_VAR_int(donotquery_localhost);
|
||||
COPY_VAR_ptr(tcp_connection_limits);
|
||||
COPY_VAR_int(auth_task_threads);
|
||||
COPY_VAR_int(harden_short_bufsize);
|
||||
COPY_VAR_int(harden_large_queries);
|
||||
COPY_VAR_int(harden_glue);
|
||||
@@ -6354,6 +6286,7 @@ fr_atomic_copy_cfg(struct config_file* oldcfg, struct config_file* cfg,
|
||||
COPY_VAR_int(harden_referral_path);
|
||||
COPY_VAR_int(harden_algo_downgrade);
|
||||
COPY_VAR_int(harden_unknown_additional);
|
||||
COPY_VAR_int(harden_cname_follow);
|
||||
COPY_VAR_int(use_caps_bits_for_id);
|
||||
COPY_VAR_ptr(caps_whitelist);
|
||||
COPY_VAR_ptr(private_address);
|
||||
@@ -7136,286 +7069,6 @@ done_error:
|
||||
}
|
||||
#endif /* !THREADS_DISABLED */
|
||||
|
||||
/** create a socketpair for bidirectional communication, false on failure */
|
||||
static int
|
||||
create_socketpair(int* pair, struct ub_randstate* rand)
|
||||
{
|
||||
#ifndef USE_WINSOCK
|
||||
if(socketpair(AF_UNIX, SOCK_STREAM, 0, pair) == -1) {
|
||||
log_err("socketpair: %s", strerror(errno));
|
||||
return 0;
|
||||
}
|
||||
(void)rand;
|
||||
#else
|
||||
struct sockaddr_in addr, baddr, accaddr, connaddr;
|
||||
socklen_t baddrlen, accaddrlen, connaddrlen;
|
||||
uint8_t localhost[] = {127, 0, 0, 1};
|
||||
uint8_t nonce[16], recvnonce[16];
|
||||
size_t i;
|
||||
int lst, pollin_event, bcount, loopcount;
|
||||
int connect_poll_timeout = 200; /* msec to wait for connection */
|
||||
ssize_t ret;
|
||||
pair[0] = -1;
|
||||
pair[1] = -1;
|
||||
for(i=0; i<sizeof(nonce); i++) {
|
||||
nonce[i] = ub_random_max(rand, 256);
|
||||
}
|
||||
lst = socket(AF_INET, SOCK_STREAM, 0);
|
||||
if(lst == -1) {
|
||||
log_err("create_socketpair: socket: %s", sock_strerror(errno));
|
||||
return 0;
|
||||
}
|
||||
memset(&addr, 0, sizeof(addr));
|
||||
addr.sin_family = AF_INET;
|
||||
addr.sin_port = 0;
|
||||
memcpy(&addr.sin_addr, localhost, 4);
|
||||
if(bind(lst, (struct sockaddr*)&addr, (socklen_t)sizeof(addr))
|
||||
== -1) {
|
||||
log_err("create socketpair: bind: %s", sock_strerror(errno));
|
||||
sock_close(lst);
|
||||
return 0;
|
||||
}
|
||||
if(listen(lst, 12) == -1) {
|
||||
log_err("create socketpair: listen: %s", sock_strerror(errno));
|
||||
sock_close(lst);
|
||||
return 0;
|
||||
}
|
||||
|
||||
pair[1] = socket(AF_INET, SOCK_STREAM, 0);
|
||||
if(pair[1] == -1) {
|
||||
log_err("create socketpair: socket: %s", sock_strerror(errno));
|
||||
sock_close(lst);
|
||||
return 0;
|
||||
}
|
||||
baddrlen = (socklen_t)sizeof(baddr);
|
||||
if(getsockname(lst, (struct sockaddr*)&baddr, &baddrlen) == -1) {
|
||||
log_err("create socketpair: getsockname: %s",
|
||||
sock_strerror(errno));
|
||||
sock_close(lst);
|
||||
sock_close(pair[1]);
|
||||
pair[1] = -1;
|
||||
return 0;
|
||||
}
|
||||
if(baddrlen > (socklen_t)sizeof(baddr)) {
|
||||
log_err("create socketpair: getsockname returned addr too big");
|
||||
sock_close(lst);
|
||||
sock_close(pair[1]);
|
||||
pair[1] = -1;
|
||||
return 0;
|
||||
}
|
||||
/* the socket is blocking */
|
||||
if(connect(pair[1], (struct sockaddr*)&baddr, baddrlen) == -1) {
|
||||
log_err("create socketpair: connect: %s",
|
||||
sock_strerror(errno));
|
||||
sock_close(lst);
|
||||
sock_close(pair[1]);
|
||||
pair[1] = -1;
|
||||
return 0;
|
||||
}
|
||||
if(!sock_poll_timeout(lst, connect_poll_timeout, 1, 0, &pollin_event)) {
|
||||
log_err("create socketpair: poll for accept failed: %s",
|
||||
sock_strerror(errno));
|
||||
sock_close(lst);
|
||||
sock_close(pair[1]);
|
||||
pair[1] = -1;
|
||||
return 0;
|
||||
}
|
||||
if(!pollin_event) {
|
||||
log_err("create socketpair: poll timeout for accept");
|
||||
sock_close(lst);
|
||||
sock_close(pair[1]);
|
||||
pair[1] = -1;
|
||||
return 0;
|
||||
}
|
||||
accaddrlen = (socklen_t)sizeof(accaddr);
|
||||
pair[0] = accept(lst, (struct sockaddr*)&accaddr, &accaddrlen);
|
||||
if(pair[0] == -1) {
|
||||
log_err("create socketpair: accept: %s", sock_strerror(errno));
|
||||
sock_close(lst);
|
||||
sock_close(pair[1]);
|
||||
pair[1] = -1;
|
||||
return 0;
|
||||
}
|
||||
if(accaddrlen > (socklen_t)sizeof(accaddr)) {
|
||||
log_err("create socketpair: accept returned addr too big");
|
||||
sock_close(lst);
|
||||
sock_close(pair[0]);
|
||||
sock_close(pair[1]);
|
||||
pair[0] = -1;
|
||||
pair[1] = -1;
|
||||
return 0;
|
||||
}
|
||||
if(accaddr.sin_family != AF_INET ||
|
||||
memcmp(localhost, &accaddr.sin_addr, 4) != 0) {
|
||||
log_err("create socketpair: accept from wrong address");
|
||||
sock_close(lst);
|
||||
sock_close(pair[0]);
|
||||
sock_close(pair[1]);
|
||||
pair[0] = -1;
|
||||
pair[1] = -1;
|
||||
return 0;
|
||||
}
|
||||
connaddrlen = (socklen_t)sizeof(connaddr);
|
||||
if(getsockname(pair[1], (struct sockaddr*)&connaddr, &connaddrlen)
|
||||
== -1) {
|
||||
log_err("create socketpair: getsockname connectedaddr: %s",
|
||||
sock_strerror(errno));
|
||||
sock_close(lst);
|
||||
sock_close(pair[0]);
|
||||
sock_close(pair[1]);
|
||||
pair[0] = -1;
|
||||
pair[1] = -1;
|
||||
return 0;
|
||||
}
|
||||
if(connaddrlen > (socklen_t)sizeof(connaddr)) {
|
||||
log_err("create socketpair: getsockname connectedaddr returned addr too big");
|
||||
sock_close(lst);
|
||||
sock_close(pair[0]);
|
||||
sock_close(pair[1]);
|
||||
pair[0] = -1;
|
||||
pair[1] = -1;
|
||||
return 0;
|
||||
}
|
||||
if(connaddr.sin_family != AF_INET ||
|
||||
memcmp(localhost, &connaddr.sin_addr, 4) != 0) {
|
||||
log_err("create socketpair: getsockname connectedaddr returned wrong address");
|
||||
sock_close(lst);
|
||||
sock_close(pair[0]);
|
||||
sock_close(pair[1]);
|
||||
pair[0] = -1;
|
||||
pair[1] = -1;
|
||||
return 0;
|
||||
}
|
||||
if(accaddr.sin_port != connaddr.sin_port) {
|
||||
log_err("create socketpair: accept from wrong port");
|
||||
sock_close(lst);
|
||||
sock_close(pair[0]);
|
||||
sock_close(pair[1]);
|
||||
pair[0] = -1;
|
||||
pair[1] = -1;
|
||||
return 0;
|
||||
}
|
||||
sock_close(lst);
|
||||
|
||||
loopcount = 0;
|
||||
bcount = 0;
|
||||
while(1) {
|
||||
if(++loopcount > IPC_LOOP_MAX) {
|
||||
log_err("create socketpair: send failed due to loop");
|
||||
sock_close(pair[0]);
|
||||
sock_close(pair[1]);
|
||||
pair[0] = -1;
|
||||
pair[1] = -1;
|
||||
return 0;
|
||||
}
|
||||
ret = send(pair[1], (void*)(nonce+bcount),
|
||||
sizeof(nonce)-bcount, 0);
|
||||
if(ret == -1) {
|
||||
if(
|
||||
#ifndef USE_WINSOCK
|
||||
errno == EINTR || errno == EAGAIN
|
||||
# ifdef EWOULDBLOCK
|
||||
|| errno == EWOULDBLOCK
|
||||
# endif
|
||||
#else
|
||||
WSAGetLastError() == WSAEINTR ||
|
||||
WSAGetLastError() == WSAEINPROGRESS ||
|
||||
WSAGetLastError() == WSAEWOULDBLOCK
|
||||
#endif
|
||||
)
|
||||
continue; /* Try again. */
|
||||
log_err("create socketpair: send: %s", sock_strerror(errno));
|
||||
sock_close(pair[0]);
|
||||
sock_close(pair[1]);
|
||||
pair[0] = -1;
|
||||
pair[1] = -1;
|
||||
return 0;
|
||||
} else if(ret+(ssize_t)bcount != sizeof(nonce)) {
|
||||
bcount += ret;
|
||||
if((size_t)bcount < sizeof(nonce))
|
||||
continue;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
if(!sock_poll_timeout(pair[0], connect_poll_timeout, 1, 0, &pollin_event)) {
|
||||
log_err("create socketpair: poll failed: %s",
|
||||
sock_strerror(errno));
|
||||
sock_close(pair[0]);
|
||||
sock_close(pair[1]);
|
||||
pair[0] = -1;
|
||||
pair[1] = -1;
|
||||
return 0;
|
||||
}
|
||||
if(!pollin_event) {
|
||||
log_err("create socketpair: poll timeout for recv");
|
||||
sock_close(pair[0]);
|
||||
sock_close(pair[1]);
|
||||
pair[0] = -1;
|
||||
pair[1] = -1;
|
||||
return 0;
|
||||
}
|
||||
|
||||
loopcount = 0;
|
||||
bcount = 0;
|
||||
while(1) {
|
||||
if(++loopcount > IPC_LOOP_MAX) {
|
||||
log_err("create socketpair: recv failed due to loop");
|
||||
sock_close(pair[0]);
|
||||
sock_close(pair[1]);
|
||||
pair[0] = -1;
|
||||
pair[1] = -1;
|
||||
return 0;
|
||||
}
|
||||
ret = recv(pair[0], (void*)(recvnonce+bcount),
|
||||
sizeof(nonce)-bcount, 0);
|
||||
if(ret == -1) {
|
||||
if(
|
||||
#ifndef USE_WINSOCK
|
||||
errno == EINTR || errno == EAGAIN
|
||||
# ifdef EWOULDBLOCK
|
||||
|| errno == EWOULDBLOCK
|
||||
# endif
|
||||
#else
|
||||
WSAGetLastError() == WSAEINTR ||
|
||||
WSAGetLastError() == WSAEINPROGRESS ||
|
||||
WSAGetLastError() == WSAEWOULDBLOCK
|
||||
#endif
|
||||
)
|
||||
continue; /* Try again. */
|
||||
log_err("create socketpair: recv: %s", sock_strerror(errno));
|
||||
sock_close(pair[0]);
|
||||
sock_close(pair[1]);
|
||||
pair[0] = -1;
|
||||
pair[1] = -1;
|
||||
return 0;
|
||||
} else if(ret == 0) {
|
||||
log_err("create socketpair: stream closed");
|
||||
sock_close(pair[0]);
|
||||
sock_close(pair[1]);
|
||||
pair[0] = -1;
|
||||
pair[1] = -1;
|
||||
return 0;
|
||||
} else if(ret+(ssize_t)bcount != sizeof(nonce)) {
|
||||
bcount += ret;
|
||||
if((size_t)bcount < sizeof(nonce))
|
||||
continue;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
if(memcmp(nonce, recvnonce, sizeof(nonce)) != 0) {
|
||||
log_err("create socketpair: recv wrong nonce");
|
||||
sock_close(pair[0]);
|
||||
sock_close(pair[1]);
|
||||
pair[0] = -1;
|
||||
pair[1] = -1;
|
||||
return 0;
|
||||
}
|
||||
#endif
|
||||
return 1;
|
||||
}
|
||||
|
||||
/** fast reload thread. setup the thread info */
|
||||
static int
|
||||
fast_reload_thread_setup(struct worker* worker, int fr_verb, int fr_nopause,
|
||||
@@ -7792,6 +7445,13 @@ auth_zone_zonemd_stop_lookup(struct auth_zone* z, struct mesh_area* mesh)
|
||||
{
|
||||
struct query_info qinfo;
|
||||
uint16_t qflags = BIT_RD;
|
||||
if(z->zonemd_transfer_active) {
|
||||
auth_load_info_release_transfer_in_progress(
|
||||
z->zonemd_callback_env);
|
||||
auth_load_schedule_waiting_pickup(z->zonemd_callback_env);
|
||||
z->zonemd_transfer_active = 0;
|
||||
}
|
||||
|
||||
qinfo.qname_len = z->namelen;
|
||||
qinfo.qname = z->name;
|
||||
qinfo.qclass = z->dclass;
|
||||
@@ -7873,6 +7533,8 @@ fr_worker_auth_del(struct worker* worker, struct fast_reload_auth_change* item,
|
||||
released = 1;
|
||||
xfr_disown_tasks(xfr, worker);
|
||||
}
|
||||
auth_load_del_zone_tasks(worker, xfr->name, xfr->namelen,
|
||||
xfr->dclass);
|
||||
lock_basic_unlock(&xfr->lock);
|
||||
}
|
||||
|
||||
|
||||
+4
-2
@@ -59,6 +59,7 @@
|
||||
#include "services/cache/infra.h"
|
||||
#include "services/cache/dns.h"
|
||||
#include "services/authzone.h"
|
||||
#include "services/authload.h"
|
||||
#include "services/mesh.h"
|
||||
#include "services/localzone.h"
|
||||
#include "services/rpz.h"
|
||||
@@ -95,8 +96,6 @@
|
||||
#include "winrc/win_svc.h"
|
||||
#endif
|
||||
|
||||
/** Size of an UDP datagram */
|
||||
#define NORMAL_UDP_SIZE 512 /* bytes */
|
||||
/** ratelimit for error responses */
|
||||
#define ERROR_RATELIMIT 100 /* qps */
|
||||
|
||||
@@ -1706,6 +1705,8 @@ worker_handle_request(struct comm_point* c, void* arg, int error,
|
||||
}
|
||||
memset(&reply_edns, 0, sizeof(reply_edns));
|
||||
reply_edns.edns_present = 1;
|
||||
reply_edns.edns_version = EDNS_ADVERTISED_VERSION;
|
||||
reply_edns.udp_size = EDNS_ADVERTISED_SIZE;
|
||||
error_encode(c->buffer, ret, &qinfo,
|
||||
*(uint16_t*)(void *)sldns_buffer_begin(c->buffer),
|
||||
sldns_buffer_read_u16_at(c->buffer, 2), &reply_edns);
|
||||
@@ -2262,6 +2263,7 @@ worker_create(struct daemon* daemon, int id)
|
||||
free(worker);
|
||||
return NULL;
|
||||
}
|
||||
rbtree_init(&worker->auth_load_tree, auth_load_tree_cmp);
|
||||
explicit_bzero(&seed, sizeof(seed));
|
||||
return worker;
|
||||
}
|
||||
|
||||
@@ -47,6 +47,7 @@
|
||||
#include "util/netevent.h"
|
||||
#include "util/locks.h"
|
||||
#include "util/alloc.h"
|
||||
#include "util/rbtree.h"
|
||||
#include "util/data/msgreply.h"
|
||||
#include "util/data/msgparse.h"
|
||||
#include "daemon/stats.h"
|
||||
@@ -135,6 +136,8 @@ struct worker {
|
||||
#endif
|
||||
/** reuse existing cache on reload if other conditions allow it. */
|
||||
int reuse_cache;
|
||||
/** tree of auth load threads, attached to this worker. */
|
||||
rbtree_type auth_load_tree;
|
||||
};
|
||||
|
||||
/**
|
||||
|
||||
@@ -968,6 +968,7 @@ dns64_adjust_ptr(struct module_qstate* qstate, struct module_qstate* super)
|
||||
if(answer) {
|
||||
answer->rk.dname = super->qinfo.qname;
|
||||
answer->rk.dname_len = super->qinfo.qname_len;
|
||||
answer->entry.hash = rrset_key_hash(&answer->rk);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
+19
-2
@@ -307,6 +307,11 @@ struct dt_io_thread* dt_io_thread_create(void)
|
||||
lock_basic_init(&dtio->wakeup_timer_lock);
|
||||
lock_protect(&dtio->wakeup_timer_lock, &dtio->wakeup_timer_enabled,
|
||||
sizeof(dtio->wakeup_timer_enabled));
|
||||
lock_basic_init(&dtio->io_list_lock);
|
||||
lock_protect(&dtio->io_list_lock, &dtio->io_list,
|
||||
sizeof(dtio->io_list));
|
||||
lock_protect(&dtio->io_list_lock, &dtio->io_list_iter,
|
||||
sizeof(dtio->io_list_iter));
|
||||
return dtio;
|
||||
}
|
||||
|
||||
@@ -315,6 +320,7 @@ void dt_io_thread_delete(struct dt_io_thread* dtio)
|
||||
struct dt_io_list_item* item, *nextitem;
|
||||
if(!dtio) return;
|
||||
lock_basic_destroy(&dtio->wakeup_timer_lock);
|
||||
lock_basic_destroy(&dtio->io_list_lock);
|
||||
item=dtio->io_list;
|
||||
while(item) {
|
||||
nextitem = item->next;
|
||||
@@ -463,9 +469,11 @@ int dt_io_thread_register_queue(struct dt_io_thread* dtio,
|
||||
mq->dtio = dtio;
|
||||
lock_basic_unlock(&mq->lock);
|
||||
item->queue = mq;
|
||||
lock_basic_lock(&dtio->io_list_lock);
|
||||
item->next = dtio->io_list;
|
||||
dtio->io_list = item;
|
||||
dtio->io_list_iter = NULL;
|
||||
lock_basic_unlock(&dtio->io_list_lock);
|
||||
return 1;
|
||||
}
|
||||
|
||||
@@ -474,6 +482,7 @@ void dt_io_thread_unregister_queue(struct dt_io_thread* dtio,
|
||||
{
|
||||
struct dt_io_list_item* item, *prev=NULL;
|
||||
if(!dtio) return;
|
||||
lock_basic_lock(&dtio->io_list_lock);
|
||||
item = dtio->io_list;
|
||||
while(item) {
|
||||
if(item->queue == mq) {
|
||||
@@ -486,11 +495,13 @@ void dt_io_thread_unregister_queue(struct dt_io_thread* dtio,
|
||||
lock_basic_unlock(&item->queue->lock);
|
||||
free(item);
|
||||
dtio->io_list_iter = NULL;
|
||||
lock_basic_unlock(&dtio->io_list_lock);
|
||||
return;
|
||||
}
|
||||
prev = item;
|
||||
item = item->next;
|
||||
}
|
||||
lock_basic_unlock(&dtio->io_list_lock);
|
||||
}
|
||||
|
||||
/** pick a message from the queue, the routine locks and unlocks,
|
||||
@@ -537,6 +548,7 @@ static int dtio_find_msg(struct dt_io_thread* dtio)
|
||||
{
|
||||
struct dt_io_list_item *spot, *item;
|
||||
|
||||
lock_basic_lock(&dtio->io_list_lock);
|
||||
spot = dtio->io_list_iter;
|
||||
/* use the next queue for the next message lookup,
|
||||
* if we hit the end(NULL) the NULL restarts the iter at start. */
|
||||
@@ -548,17 +560,22 @@ static int dtio_find_msg(struct dt_io_thread* dtio)
|
||||
/* scan from spot to end-of-io_list */
|
||||
item = spot;
|
||||
while(item) {
|
||||
if(dtio_find_in_queue(dtio, item->queue))
|
||||
if(dtio_find_in_queue(dtio, item->queue)) {
|
||||
lock_basic_unlock(&dtio->io_list_lock);
|
||||
return 1;
|
||||
}
|
||||
item = item->next;
|
||||
}
|
||||
/* scan starting at the start-of-list (to wrap around the end) */
|
||||
item = dtio->io_list;
|
||||
while(item) {
|
||||
if(dtio_find_in_queue(dtio, item->queue))
|
||||
if(dtio_find_in_queue(dtio, item->queue)) {
|
||||
lock_basic_unlock(&dtio->io_list_lock);
|
||||
return 1;
|
||||
}
|
||||
item = item->next;
|
||||
}
|
||||
lock_basic_unlock(&dtio->io_list_lock);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
@@ -123,6 +123,8 @@ struct dt_io_thread {
|
||||
int threadnum;
|
||||
/** event base, for event handling */
|
||||
void* event_base;
|
||||
/** lock on io_list and io_list_iter */
|
||||
lock_basic_type io_list_lock;
|
||||
/** list of queues that is registered to get written */
|
||||
struct dt_io_list_item* io_list;
|
||||
/** iterator point in the io_list, to pick from them in a
|
||||
|
||||
+248
@@ -1,3 +1,251 @@
|
||||
21 October 2026: Wouter
|
||||
- Release of 1.26.2 with the following security fixes.
|
||||
- Fix CVE-2026-97206, DoQ path-migration can lead to use-after-free on
|
||||
multi-threaded deployments. Thanks to Kunta Chu and Jianjun Chen
|
||||
from Tsinghua University for the report.
|
||||
- Fix CVE-2026-50106, Possible insecure NXDOMAIN for non-existing
|
||||
records under a configured island trust anchor underneath an
|
||||
insecure parent. Thanks to Qifan Zhang from Palo Alto Networks
|
||||
for the report.
|
||||
- Fix CVE-2026-96405, Aggregate DNS name chained pointer decompression
|
||||
work leads to degradation of service. Thanks to Yuheng Zhang
|
||||
(Tsinghua University and Jingxian Technology Co., Ltd.), Jianjun
|
||||
Chen (Tsinghua University), Zihan Wang (Z.AI Co., Ltd.) and Kaiwen
|
||||
Shen (CloudItera) for the report.
|
||||
- Fix CVE-2026-109125, Possible cache poisoning vulnerability via
|
||||
a cache side-channel exposed by 'unwanted-reply-threshold'. Thanks
|
||||
to TaoFei Guo (Peking University), and Yang Luo and JianJun Chen
|
||||
(Tsinghua University) for the report.
|
||||
- Fix CVE-2026-35501, Bypass of a configured island trust anchor
|
||||
underneath an insecure parent from an attacker-controlled NSEC
|
||||
record. Thanks to Qifan Zhang from Palo Alto Networks for the
|
||||
report.
|
||||
- The code repository continues with 1.26.3 under development,
|
||||
that includes the changes from before the 1.26.2 commits.
|
||||
- Unit test for CVE-2026-50106.
|
||||
- Unit test for CVE-2026-35501.
|
||||
- Fix dynlibmod test for inplace callback termination.
|
||||
|
||||
20 October 2026: Willem
|
||||
- Merge #1539: Send along ETag with auth zone xfrs over http(s),
|
||||
so Unbound will not fetch the whole zone every refresh time,
|
||||
but only when it has changed.
|
||||
|
||||
20 October 2026: Wouter
|
||||
- Merge #1534: unbound-checkconf reads config, but zonefiles
|
||||
are read with an option, '-a'. This speeds up the checkconf
|
||||
before server start in the presence of large zone files.
|
||||
And it is similar to how nsd-checkconf behaves.
|
||||
- Fix testbound so that it does not reference an already
|
||||
deleted pending packet, but its packet contents, when
|
||||
removing from the pending list.
|
||||
- Fix to remove debug print from unit test.
|
||||
- Fix testbound to free reference pending packet.
|
||||
|
||||
20 October 2026: Yorgos
|
||||
- Add CONTRIBUTING.md, similar to other NLnet Labs projects.
|
||||
- Merge #1536: Better documentation and warning message for no
|
||||
configured trust anchors.
|
||||
- Terminate inplace callback progression if one of them errors out;
|
||||
suggestion by Rio Fujita.
|
||||
|
||||
19 October 2026: Wouter
|
||||
- Merge #1528 from Ar-maan05: Fix NSEC at apex detection for
|
||||
short type bitmaps.
|
||||
- Merge #1531 from nshopik: Fix dnstap queue registration race
|
||||
between worker threads.
|
||||
- Merge #1532 from Ar-maan05: Fix packet position after a
|
||||
short RRSIG in pkt_rrsig_covered.
|
||||
|
||||
16 October 2026: Wouter
|
||||
- Fix unit test for root_zonemd with updated root key.
|
||||
|
||||
13 October 2026: Wouter
|
||||
- Fix dns64 synthesis and cache with subnet module enabled.
|
||||
The subnet module stopped a cache store, that caused later
|
||||
dns64 replies to have a nodata answer for the AAAA.
|
||||
|
||||
13 October 2026: Yorgos
|
||||
- Fix #1526: Root Server h.root-servers.net has been included for Zone
|
||||
Transfer Service by including it in the example configuration.
|
||||
|
||||
2 October 2026: Yorgos
|
||||
- Document libunbound's context lifetime during an async callback.
|
||||
Thanks to Omar Mousa for the suggestion.
|
||||
|
||||
28 September 2026: Wouter
|
||||
- Fix to log the errno for trust anchor write close fail.
|
||||
- Merge #1518 from nshopik: rrset: rehash copies after
|
||||
changing the key.
|
||||
- Fix to allow for large (64Kb) packets with testbound.
|
||||
|
||||
22 September 2026: Yorgos
|
||||
- Fix #1514: [FR] do-not-query-localhost is not including
|
||||
0.0.0.0/8 and ‘::’ in the man page.
|
||||
- Fix #1513: [FR] Size of harden-large-queries in the man page.
|
||||
- Move NORMAL_UDP_SIZE around.
|
||||
- Clarify man page text for harden-short-bufsize.
|
||||
- Update generated man pages.
|
||||
|
||||
21 September 2026: Yorgos
|
||||
- Merge #1510 from Andy Warner: Move unlink of temp file to before
|
||||
fatal exit.
|
||||
|
||||
16 September 2026: Wouter
|
||||
- Release of 1.26.1 with the following security fixes.
|
||||
- Fix CVE-2026-81642, Heap buffer overflow and possible Remote Code
|
||||
Execution when digesting DNSKEY. Thanks to Yuqi Qiu and Xiang Li
|
||||
from Nankai University, AOSP Lab for the report.
|
||||
- Fix CVE-2026-81634, Possible heap buffer overflow during DNSSEC
|
||||
canonicalization. Thanks to Vlatko Kosturjak with Marlink Cyber,
|
||||
for the report.
|
||||
- Fix CVE-2026-82717, CNAME synthesis could lead to heap corruption.
|
||||
Thanks to Ben Morris from Anthropic for the report.
|
||||
- Fix CVE-2026-77955, Possible ZONEMD verification bypass window.
|
||||
Thanks to Yuqi Qiu and Xiang Li from Nankai University, AOSP Lab,
|
||||
for the report. In addition, thanks to Qifan Zhang from Palo Alto
|
||||
Networks for also reporting this issue.
|
||||
- Fix CVE-2026-78227, Use-after-free in DoQ stream output buffer on
|
||||
reset re-transmission. Thanks to Yuqi Qiu and Xiang Li from Nankai
|
||||
University, AOSP Lab for the report.
|
||||
- Fix CVE-2026-80225, Possible degradation of service from continuous
|
||||
queries on the same TCP/DoT connection. Thanks to Qifan Zhang from
|
||||
Palo Alto Networks for the report.
|
||||
- Fix CVE-2026-82720, Use-after-free in DoH stream cleanup code path.
|
||||
Thanks to Yuqi Qiu and Xiang Li from Nankai University, AOSP Lab,
|
||||
for the report.
|
||||
- Fix CVE-2026-85501, Retrap: Novel Vulnerabilities to launch
|
||||
Algorithmic Complexity Attacks on DNSSEC. Thanks to Zuyao Xu and
|
||||
Xiang Li from Nankai University, AOSP Lab for the report. In
|
||||
addition, thanks to Qifan Zhang from Palo Alto Networks for a
|
||||
complimentary report.
|
||||
- Fix CVE-2026-77860, 'serve-expired' can bypass Unbound 'wait-limit'.
|
||||
Thanks to Xuanchao Xie, Lutong Chen, and Kaiping Xue from the
|
||||
University of Science and Technology of China (USTC) for the
|
||||
report.
|
||||
- The code repository continues with 1.26.2 under development,
|
||||
that includes the changes from before the 1.26.1 commits.
|
||||
- Unit test for CVE-2026-81642.
|
||||
- Unit test for CVE-2026-82717.
|
||||
- Unit test for CVE-2026-85501.
|
||||
|
||||
15 September 2026: Wouter
|
||||
- For #1507: TOCTOU race in store_rrsets() can return a
|
||||
CNAME chain whose target owns no address.
|
||||
|
||||
10 September 2026: Wouter
|
||||
- Fix to construct the delegation point during DS NS find
|
||||
as a child side delegation point if that was the response.
|
||||
Thanks to Qifan Zhang, Palo Alto Networks, for the report.
|
||||
- Fix to error on missing close parenthesis for zone file
|
||||
read and for url content read. Thanks to Qifan Zhang, Palo
|
||||
Alto Networks, for the report.
|
||||
|
||||
8 September 2026: Wouter
|
||||
- Fix to elevate the diagnostic for no matches for a wildcard
|
||||
trusted-keys-file, make it more descriptive, and more man
|
||||
page content for it. Thanks to Qifan Zhang, Palo Alto
|
||||
Networks, for the report.
|
||||
|
||||
4 September 2026: Wouter
|
||||
- Fix to make rpz_config leave the rpz with correct set up
|
||||
on failure. The struct is not half configured on exit.
|
||||
Thanks to Qifan Zhang, Palo Alto Networks, for the report.
|
||||
- Fix to not change the action override in rpz_config, before
|
||||
the cname override has succeeded.
|
||||
|
||||
3 September 2026: Wouter
|
||||
- Fix to match NSEC3 hash length to the NSEC3 algorithm,
|
||||
this stops negative cache overdeletion. It also contrains
|
||||
the hash label length and checks if the NSEC nextowner
|
||||
is valid. Thanks to Yuqi Qiu & Xiang Li (Nankai University,
|
||||
AOSP Lab).
|
||||
- Remove unused .travis.yml for ci integration.
|
||||
- Fix to reorder SVCB and HTTPS svcparams for unknown RR form
|
||||
zonefile input. If it can not be parsed it is leniently
|
||||
accepted, much like as a secondary it leniently accepts it.
|
||||
Thanks to Qifan Zhang, Palo Alto Networks, for the report.
|
||||
- Fix that when extended EDNS RCODE does not fit, at short
|
||||
udpsize, the reply is truncated with TC and fix for the
|
||||
rcode in that short reply to be a sensible rcode.
|
||||
Thanks to Qifan Zhang, Palo Alto Networks, for the report.
|
||||
- Fix that when a partial EDNS option is in a query, the
|
||||
response is a more RFC conformant FORMERR, since the EDNS
|
||||
option is malformed. Also fix to have an EDNS size for
|
||||
the reply error encoding for failed EDNS parse of the query.
|
||||
Thanks to Qifan Zhang, Palo Alto Networks, for the report.
|
||||
|
||||
2 September 2026: Wouter
|
||||
- Fix to not commit to have_zone at apply AXFR time for auth
|
||||
zone transfers, so that later failure rolls back to not.
|
||||
The have_zone value is set later when the SOA is retrieved.
|
||||
Also fix to clear the zone data when a transfer does not
|
||||
have a valid SOA record in the zone for it.
|
||||
Thanks to Qifan Zhang, Palo Alto Networks, for the report.
|
||||
|
||||
1 September 2026: Wouter
|
||||
- Fix to allow block_a and other local-zone types in a view.
|
||||
- Fix LOC RR parse to avoid double to uint32 cast overflow.
|
||||
Thanks to Qifan Zhang, Palo Alto Networks, for the report.
|
||||
|
||||
26 August 2026: Wouter
|
||||
- Fix notify for auth-zone during initial start up. It
|
||||
performs the transfer and not only lookup.
|
||||
|
||||
24 August 2026: Wouter
|
||||
- Fix #132: Add `harden-cname-follow: yes` config option, that
|
||||
can be used to disable cname scrubbing. That can be useful
|
||||
for when the traffic is on localhost only.
|
||||
|
||||
21 August 2026: Wouter
|
||||
- Fix to defend against double event deletion, that could cause
|
||||
event corruption and use after free, for comm_timer_disable.
|
||||
|
||||
11 August 2026: Wouter
|
||||
- Fix #1492 from zacek: Data race in log_init() on
|
||||
key_created/log_lock when calling ub_ctx_create()
|
||||
concurrently from multiple threads.
|
||||
- Fix stat_values.tdir test to have less test failures.
|
||||
|
||||
7 August 2026: Wouter
|
||||
- Fix #1489 from jplesnik: Replace removed Python 2 C API
|
||||
macros for SWIG 4.5.0 compatibility.
|
||||
|
||||
6 August 2026: Alex Khanin
|
||||
- Fix #1488: bounds check in packed_rr_to_string, it checked
|
||||
the assembled rr length against the output string length
|
||||
dest_len, instead of against the size of the rr buffer it
|
||||
writes into. Callers in cachedump.c and remote.c pass a
|
||||
dest_len larger than that buffer.
|
||||
- Unit test for packed_rr_to_string.
|
||||
|
||||
6 August 2026: Wouter
|
||||
- Fix #1485: the list_forwards command omits port numbers.
|
||||
The list_forwards and list_stubs commands for
|
||||
unbound-control print port and tls auth name.
|
||||
- Fix #1487: regression in 1.26.0, ipsecmod is now always
|
||||
partly enabled.
|
||||
|
||||
4 August 2026: Wouter
|
||||
- Fix to set makedist.sh to not wget config.sub and
|
||||
config.guess from git repo. The fetch times out, and the
|
||||
version from libtoolize is much more recent now than
|
||||
that it was when the wget was added.
|
||||
|
||||
31 July 2026: Wouter
|
||||
- For #1483: The failure reason when an NSEC NXDOMAIN is
|
||||
encountered when looking for an insecure delegation, is
|
||||
fixed to mention the NSEC records, instead of nonexistent
|
||||
NSEC3 records, that it attempted.
|
||||
|
||||
30 July 2026: Wouter
|
||||
- Fix #1482: DNS-over-QUIC doesn't work with simple config.
|
||||
That fixes interface-automatic for use with doq service.
|
||||
|
||||
28 July 2026: Wouter
|
||||
- Tag for 1.26.0rc1. The repo continues with version 1.26.1.
|
||||
This became 1.26.0 on 4 aug 2026.
|
||||
|
||||
24 July 2026: Wouter
|
||||
- Merge #1433 from jisakiel: Add new static zone type
|
||||
block_aaaa to suppress AAAA queries.
|
||||
|
||||
@@ -588,6 +588,9 @@ server:
|
||||
# additional section.
|
||||
# harden-unknown-additional: no
|
||||
|
||||
# Harden CNAME redirections by following them.
|
||||
# harden-cname-follow: yes
|
||||
|
||||
# Sent minimum amount of information to upstream servers to enhance
|
||||
# privacy. Only sent minimum required labels of the QNAME and set QTYPE
|
||||
# to A when possible.
|
||||
@@ -669,6 +672,7 @@ server:
|
||||
# most modules have to be listed at the beginning of the line,
|
||||
# except cachedb(just before iterator), and python (at the beginning,
|
||||
# or, just before the iterator).
|
||||
# Note that validator needs configured trust-anchors to be of any use.
|
||||
# module-config: "validator iterator"
|
||||
|
||||
# File with trusted keys, kept up-to-date using RFC5011 probes,
|
||||
@@ -1168,6 +1172,8 @@ server:
|
||||
# Timeout in milliseconds for TCP queries to auth servers.
|
||||
# tcp-auth-query-timeout: 3000
|
||||
|
||||
# Number of threads to use to load auth-zones (and RPZ). 0 disables.
|
||||
# auth-task-threads: 0
|
||||
|
||||
# Python config section. To enable:
|
||||
# o use --with-pythonmodule to configure before compiling.
|
||||
@@ -1276,6 +1282,7 @@ remote-control:
|
||||
# primary: 199.7.91.13 # d.root-servers.net
|
||||
# primary: 192.5.5.241 # f.root-servers.net
|
||||
# primary: 192.112.36.4 # g.root-servers.net
|
||||
# primary: 198.97.190.53 # h.root-servers.net
|
||||
# primary: 193.0.14.129 # k.root-servers.net
|
||||
# primary: 192.0.47.132 # xfr.cjr.dns.icann.org
|
||||
# primary: 192.0.32.132 # xfr.lax.dns.icann.org
|
||||
@@ -1284,6 +1291,7 @@ remote-control:
|
||||
# primary: 2001:500:2d::d # d.root-servers.net
|
||||
# primary: 2001:500:2f::f # f.root-servers.net
|
||||
# primary: 2001:500:12::d0d # g.root-servers.net
|
||||
# primary: 2001:500:1::53 # h.root-servers.net
|
||||
# primary: 2001:7fd::1 # k.root-servers.net
|
||||
# primary: 2620:0:2830:202::132 # xfr.cjr.dns.icann.org
|
||||
# primary: 2620:0:2d0:202::132 # xfr.lax.dns.icann.org
|
||||
|
||||
@@ -331,6 +331,8 @@ void my_callback_function(void* my_arg, int err,
|
||||
The \fBasync_id\fP is returned so you can (at your option) decide to
|
||||
track it and cancel the request if needed.
|
||||
If you pass a NULL pointer the \fBasync_id\fP is not returned.
|
||||
The context, created via \fBub_ctx_create\fP, is in use during but also
|
||||
after the callback and it cannot be deleted during a callback.
|
||||
.TP
|
||||
.B ub_cancel
|
||||
Cancel an async query in progress.
|
||||
|
||||
@@ -408,6 +408,8 @@ Functions
|
||||
The **async_id** is returned so you can (at your option) decide to
|
||||
track it and cancel the request if needed.
|
||||
If you pass a NULL pointer the **async_id** is not returned.
|
||||
The context, created via **ub_ctx_create**, is in use during but also
|
||||
after the callback and it cannot be deleted during a callback.
|
||||
|
||||
ub_cancel
|
||||
Cancel an async query in progress.
|
||||
|
||||
@@ -42,7 +42,7 @@ unbound-checkconf(8)
|
||||
Synopsis
|
||||
--------
|
||||
|
||||
**unbound-checkconf** [``-hf``] [``-o option``] [cfgfile]
|
||||
**unbound-checkconf** [``-ahf``] [``-o option``] [cfgfile]
|
||||
|
||||
Description
|
||||
-----------
|
||||
@@ -54,6 +54,11 @@ The config file syntax is described in
|
||||
|
||||
The available options are:
|
||||
|
||||
.. option:: -a
|
||||
|
||||
Also read the zonefiles for auth-zones and RPZ.
|
||||
It checks if the syntax is okay of the zonefiles.
|
||||
|
||||
.. option:: -h
|
||||
|
||||
Show the version and commandline option help.
|
||||
|
||||
+45
-3
@@ -2070,7 +2070,8 @@ Default: \(dq3 2 1 0 0\(dq
|
||||
.INDENT 0.0
|
||||
.TP
|
||||
.B harden\-short\-bufsize: \fI<yes or no>\fP
|
||||
Very small EDNS buffer sizes from queries are ignored.
|
||||
Very small EDNS buffer sizes from queries are ignored and are instead
|
||||
set to the normal UDP packet size (512 bytes).
|
||||
.sp
|
||||
Default: yes (per \fI\%RFC 6891\fP)
|
||||
.UNINDENT
|
||||
@@ -2078,6 +2079,7 @@ Default: yes (per \fI\%RFC 6891\fP)
|
||||
.TP
|
||||
.B harden\-large\-queries: \fI<yes or no>\fP
|
||||
Very large queries are ignored.
|
||||
The cutoff value is chosen to be the normal UDP packet size (512 bytes).
|
||||
Default is no, since it is legal protocol wise to send these, and could be
|
||||
necessary for operation if TSIG or EDNS payload is very large.
|
||||
.sp
|
||||
@@ -2201,6 +2203,18 @@ Default: no
|
||||
.UNINDENT
|
||||
.INDENT 0.0
|
||||
.TP
|
||||
.B harden\-cname\-follow: \fI<yes or no>\fP
|
||||
Harden CNAME redirections by following them.
|
||||
If no, then upstream CNAME and DNAME redirections are allowed in a
|
||||
response without checking with further messages if those are valid.
|
||||
It can only really be disabled safely on localhost net or encrypted
|
||||
connectivity.
|
||||
Default is on to protect the cache integrity.
|
||||
.sp
|
||||
Default: yes
|
||||
.UNINDENT
|
||||
.INDENT 0.0
|
||||
.TP
|
||||
.B use\-caps\-for\-id: \fI<yes or no>\fP
|
||||
Use 0x20\-encoded random bits in the query to foil spoof attempts.
|
||||
This perturbs the lowercase and uppercase of query names sent to authority
|
||||
@@ -2336,7 +2350,10 @@ Default: (none)
|
||||
.B do\-not\-query\-localhost: \fI<yes or no>\fP
|
||||
If yes, localhost is added to the
|
||||
\fI\%do\-not\-query\-address\fP entries,
|
||||
both IPv6 \fB::1\fP and IPv4 \fB127.0.0.1/8\fP\&.
|
||||
both IPv4 \fB127.0.0.1/8\fP (also \fB::ffff:127.0.0.0/104\fP) and IPv6 \fB::1\fP\&.
|
||||
Additionally, the zero subnets \fB0.0.0.0/8\fP (also \fB::ffff:0:0/96\fP) and
|
||||
\fB::\fP are added to the list since on some systems they route to
|
||||
localhost as well.
|
||||
If no, then localhost can be used to send queries to.
|
||||
.sp
|
||||
Default: yes
|
||||
@@ -2504,6 +2521,9 @@ Format is BIND\-9 style format, the \fBtrusted\-keys { name flag proto algo
|
||||
It is possible to use wildcards with this statement, the wildcard is
|
||||
expanded on start and on reload.
|
||||
.sp
|
||||
A wildcard that matches no files is not an error: the entry loads no
|
||||
trust anchors, and the condition is logged at operational verbosity.
|
||||
.sp
|
||||
Default: \(dq\(dq (no trusted keys file)
|
||||
.UNINDENT
|
||||
.INDENT 0.0
|
||||
@@ -2613,7 +2633,7 @@ affected.
|
||||
Use this setting to protect the users that rely on this validator for
|
||||
authentication from potentially bad data in the additional section.
|
||||
.sp
|
||||
Default: yes
|
||||
Default: no
|
||||
.UNINDENT
|
||||
.INDENT 0.0
|
||||
.TP
|
||||
@@ -3879,6 +3899,28 @@ Default: yes
|
||||
.UNINDENT
|
||||
.INDENT 0.0
|
||||
.TP
|
||||
.B val\-validation\-attempts: \fI<number>\fP
|
||||
Limit on the number of DNSSEC validation attempts for a query.
|
||||
This protects against too large numbers of cryptographic operations,
|
||||
like for a deep delegation chain.
|
||||
This counts attempts to validate RRSIGs.
|
||||
When it is exceeded, the query fails.
|
||||
.sp
|
||||
Default: 32
|
||||
.UNINDENT
|
||||
.INDENT 0.0
|
||||
.TP
|
||||
.B val\-hash\-attempts: \fI<number>\fP
|
||||
Limit on the number of DNSSEC hash attempts for a query.
|
||||
This protects against too large numbers of cryptographic operations,
|
||||
like for a deep delegation chain.
|
||||
This counts DS hash attempts to match DNSKEYs.
|
||||
When it is exceeded, the query fails.
|
||||
.sp
|
||||
Default: 32
|
||||
.UNINDENT
|
||||
.INDENT 0.0
|
||||
.TP
|
||||
.B fast\-server\-permil: \fI<number>\fP
|
||||
Specify how many times out of 1000 to pick from the set of fastest servers.
|
||||
0 turns the feature off.
|
||||
|
||||
+43
-5
@@ -1838,13 +1838,15 @@ These options are part of the ``server:`` section.
|
||||
|
||||
|
||||
@@UAHL@unbound.conf@harden-short-bufsize@@: *<yes or no>*
|
||||
Very small EDNS buffer sizes from queries are ignored.
|
||||
Very small EDNS buffer sizes from queries are ignored and are instead
|
||||
set to the normal UDP packet size (512 bytes).
|
||||
|
||||
Default: yes (per :rfc:`6891`)
|
||||
|
||||
|
||||
@@UAHL@unbound.conf@harden-large-queries@@: *<yes or no>*
|
||||
Very large queries are ignored.
|
||||
The cutoff value is chosen to be the normal UDP packet size (512 bytes).
|
||||
Default is no, since it is legal protocol wise to send these, and could be
|
||||
necessary for operation if TSIG or EDNS payload is very large.
|
||||
|
||||
@@ -1952,6 +1954,17 @@ These options are part of the ``server:`` section.
|
||||
Default: no
|
||||
|
||||
|
||||
@@UAHL@unbound.conf@harden-cname-follow@@: *<yes or no>*
|
||||
Harden CNAME redirections by following them.
|
||||
If no, then upstream CNAME and DNAME redirections are allowed in a
|
||||
response without checking with further messages if those are valid.
|
||||
It can only really be disabled safely on localhost net or encrypted
|
||||
connectivity.
|
||||
Default is on to protect the cache integrity.
|
||||
|
||||
Default: yes
|
||||
|
||||
|
||||
@@UAHL@unbound.conf@use-caps-for-id@@: *<yes or no>*
|
||||
Use 0x20-encoded random bits in the query to foil spoof attempts.
|
||||
This perturbs the lowercase and uppercase of query names sent to authority
|
||||
@@ -2077,7 +2090,10 @@ These options are part of the ``server:`` section.
|
||||
@@UAHL@unbound.conf@do-not-query-localhost@@: *<yes or no>*
|
||||
If yes, localhost is added to the
|
||||
:ref:`do-not-query-address<unbound.conf.do-not-query-address>` entries,
|
||||
both IPv6 ``::1`` and IPv4 ``127.0.0.1/8``.
|
||||
both IPv4 ``127.0.0.1/8`` (also ``::ffff:127.0.0.0/104``) and IPv6 ``::1``.
|
||||
Additionally, the zero subnets ``0.0.0.0/8`` (also ``::ffff:0:0/96``) and
|
||||
``::`` are added to the list since on some systems they route to
|
||||
localhost as well.
|
||||
If no, then localhost can be used to send queries to.
|
||||
|
||||
Default: yes
|
||||
@@ -2155,11 +2171,12 @@ These options are part of the ``server:`` section.
|
||||
The ordering of the modules is significant, the order decides the order
|
||||
of processing.
|
||||
|
||||
Setting this to just "iterator" will result in a non-validating server.
|
||||
Setting this to "validator iterator" will turn on DNSSEC validation.
|
||||
Setting this to just ``"iterator"`` results in a non-validating server.
|
||||
Setting this to ``"validator iterator"`` (default) enables the DNSSEC
|
||||
validator module but not DNSSEC validation.
|
||||
|
||||
.. note::
|
||||
You must also set trust-anchors for validation to be useful.
|
||||
To turn on DNSSEC validation you must configure trust-anchors.
|
||||
|
||||
Adding ``respip`` to the front will cause RPZ processing to be done on all
|
||||
queries.
|
||||
@@ -2226,6 +2243,9 @@ These options are part of the ``server:`` section.
|
||||
It is possible to use wildcards with this statement, the wildcard is
|
||||
expanded on start and on reload.
|
||||
|
||||
A wildcard that matches no files is not an error: the entry loads no
|
||||
trust anchors, and the condition is logged at operational verbosity.
|
||||
|
||||
Default: "" (no trusted keys file)
|
||||
|
||||
|
||||
@@ -3501,6 +3521,24 @@ These options are part of the ``server:`` section.
|
||||
|
||||
Default: no
|
||||
|
||||
|
||||
@@UAHL@unbound.conf@auth-task-threads@@: *<number of threads>*
|
||||
If nonzero, the number of threads to start to process zone transfers
|
||||
for authority zones, and also RPZ zones.
|
||||
The zone transfer is processed in a thread, that does not interrupt
|
||||
the resolver.
|
||||
For RPZ zones that means the old RPZ zone continues to be used, while
|
||||
the task is processed.
|
||||
The thread allocates the new zone data, and this keeps another copy of
|
||||
the zone data in memory during processing.
|
||||
The result is swapped into the resolver when the thread is done.
|
||||
|
||||
The value 0 disables the threading, one of the worker threads performs
|
||||
the processing. Without threading enabled, use the value 0.
|
||||
|
||||
Default: 0
|
||||
|
||||
|
||||
.. _unbound.conf.remote:
|
||||
|
||||
Remote Control Options
|
||||
|
||||
@@ -128,5 +128,5 @@ int reply_callback(struct query_info* qinfo,
|
||||
((int *)env->dyn_env)[1],
|
||||
((int *)env->dyn_env)[2]);
|
||||
}
|
||||
return 0;
|
||||
return 1;
|
||||
}
|
||||
|
||||
@@ -1167,7 +1167,8 @@ subnetmod_operate(struct module_qstate *qstate, enum module_ev event,
|
||||
subnet_ecs_opt_list_append(&sq->ecs_client_out,
|
||||
&qstate->edns_opts_front_out, qstate,
|
||||
qstate->region);
|
||||
qstate->is_subnet_answer = 1;
|
||||
if(sq->subnet_sent || sq->subnet_sent_no_subnet)
|
||||
qstate->is_subnet_answer = 1;
|
||||
if(verbosity >= VERB_ALGO) {
|
||||
subnet_log_print("reply has edns subnet",
|
||||
edns_opt_list_find(
|
||||
|
||||
+7
-3
@@ -59,6 +59,11 @@
|
||||
static int
|
||||
ipsecmod_apply_cfg(struct ipsecmod_env* ipsecmod_env, struct config_file* cfg)
|
||||
{
|
||||
if(cfg->ipsecmod_whitelist &&
|
||||
!ipsecmod_whitelist_apply_cfg(ipsecmod_env, cfg))
|
||||
return 0;
|
||||
if(!cfg->ipsecmod_enabled)
|
||||
return 1;
|
||||
if(!cfg->ipsecmod_hook || (cfg->ipsecmod_hook && !cfg->ipsecmod_hook[0])) {
|
||||
log_err("ipsecmod: missing ipsecmod-hook.");
|
||||
return 0;
|
||||
@@ -68,9 +73,6 @@ ipsecmod_apply_cfg(struct ipsecmod_env* ipsecmod_env, struct config_file* cfg)
|
||||
cfg->ipsecmod_hook, strerror(errno));
|
||||
return 0;
|
||||
}
|
||||
if(cfg->ipsecmod_whitelist &&
|
||||
!ipsecmod_whitelist_apply_cfg(ipsecmod_env, cfg))
|
||||
return 0;
|
||||
return 1;
|
||||
}
|
||||
|
||||
@@ -626,6 +628,8 @@ ipsecmod_inform_super(struct module_qstate* qstate, int id,
|
||||
verbose(VERB_ALGO, "super has no ipsecmod state");
|
||||
return;
|
||||
}
|
||||
if(!siq->enabled)
|
||||
return;
|
||||
|
||||
if(qstate->return_msg) {
|
||||
struct ub_packed_rrset_key* rrset_key = reply_find_answer_rrset(
|
||||
|
||||
@@ -46,6 +46,7 @@
|
||||
#include "services/cache/dns.h"
|
||||
#include "util/net_help.h"
|
||||
#include "util/data/dname.h"
|
||||
#include "util/config_file.h"
|
||||
#include "sldns/rrdef.h"
|
||||
#include "sldns/pkthdr.h"
|
||||
|
||||
@@ -107,7 +108,8 @@ response_type_from_cache(struct dns_msg* msg,
|
||||
enum response_type
|
||||
response_type_from_server(int rdset,
|
||||
struct dns_msg* msg, struct query_info* request, struct delegpt* dp,
|
||||
int* empty_nodata_found, int msg_lame_empty, int msg_lame_referral)
|
||||
int* empty_nodata_found, int msg_lame_empty, int msg_lame_referral,
|
||||
struct config_file* cfg)
|
||||
{
|
||||
uint8_t* origzone = (uint8_t*)"\000"; /* the default */
|
||||
struct ub_packed_rrset_key* s;
|
||||
@@ -130,6 +132,16 @@ response_type_from_server(int rdset,
|
||||
if( (msg->rep->flags&BIT_RA) &&
|
||||
!(msg->rep->flags&BIT_AA) && !rdset)
|
||||
return RESPONSE_TYPE_REC_LAME;
|
||||
if(!cfg->harden_cname_follow /* follow CNAME chain */) {
|
||||
/* If the CNAME chain is allowed, see if there is a
|
||||
* SOA record, if so, the chain is complete to the
|
||||
* end of it, otherwise it could be a partial chain.*/
|
||||
for(i=msg->rep->an_numrrsets; i<msg->rep->an_numrrsets+msg->rep->ns_numrrsets; i++) {
|
||||
s = msg->rep->rrsets[i];
|
||||
if(ntohs(s->rk.type) == LDNS_RR_TYPE_SOA)
|
||||
return RESPONSE_TYPE_ANSWER;
|
||||
}
|
||||
}
|
||||
/* it could be a CNAME with NXDOMAIN rcode */
|
||||
for(i=0; i<msg->rep->an_numrrsets; i++) {
|
||||
s = msg->rep->rrsets[i];
|
||||
@@ -162,6 +174,7 @@ response_type_from_server(int rdset,
|
||||
if(msg->rep->an_numrrsets > 0) {
|
||||
uint8_t* mname = request->qname;
|
||||
size_t mname_len = request->qname_len;
|
||||
int sawanswer = 0;
|
||||
|
||||
/* Now look at the answer section first. 3 states: our
|
||||
* answer is there directly, our answer is there after
|
||||
@@ -197,6 +210,7 @@ response_type_from_server(int rdset,
|
||||
* the answer, we only provisionally say
|
||||
* 'ANSWER' -- it very well could be a
|
||||
* REFERRAL. */
|
||||
sawanswer = 1;
|
||||
break;
|
||||
}
|
||||
|
||||
@@ -214,6 +228,10 @@ response_type_from_server(int rdset,
|
||||
* still got to here, then it is a CNAME response.
|
||||
* (This is regardless of the AA bit at this point) */
|
||||
if(mname != request->qname) {
|
||||
if(!cfg->harden_cname_follow /* allow CNAMEs */ &&
|
||||
sawanswer /* The last was not CNAME, and
|
||||
there is an answer RRset. */ )
|
||||
return RESPONSE_TYPE_ANSWER;
|
||||
return RESPONSE_TYPE_CNAME;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -45,6 +45,7 @@
|
||||
struct dns_msg;
|
||||
struct query_info;
|
||||
struct delegpt;
|
||||
struct config_file;
|
||||
|
||||
/**
|
||||
* The response type is used to interpret the response.
|
||||
@@ -115,7 +116,7 @@ enum response_type response_type_from_cache(struct dns_msg* msg,
|
||||
* detection, mostly).
|
||||
*
|
||||
* @param rdset: if RD bit was sent in query sent by unbound.
|
||||
* @param msg: the message from the cache.
|
||||
* @param msg: the message.
|
||||
* @param request: the request that generated the response.
|
||||
* @param dp: The delegation point that was being queried
|
||||
* when the response was returned.
|
||||
@@ -124,10 +125,12 @@ enum response_type response_type_from_cache(struct dns_msg* msg,
|
||||
* is lame, before it became empty.
|
||||
* @param msg_lame_referral: returned true if the reply has a referral before
|
||||
* scrub.
|
||||
* @param cfg: config with options.
|
||||
* @return the response type (CNAME or ANSWER).
|
||||
*/
|
||||
enum response_type response_type_from_server(int rdset,
|
||||
struct dns_msg* msg, struct query_info* request, struct delegpt* dp,
|
||||
int* empty_nodata_found, int msg_lame_empty, int msg_lame_referral);
|
||||
int* empty_nodata_found, int msg_lame_empty, int msg_lame_referral,
|
||||
struct config_file* cfg);
|
||||
|
||||
#endif /* ITERATOR_ITER_RESPTYPE_H */
|
||||
|
||||
+28
-4
@@ -524,7 +524,7 @@ scrub_normalize(sldns_buffer* pkt, struct msg_parse* msg,
|
||||
* server, scrub down the length to something
|
||||
* shorter. This deletes everything after the limit
|
||||
* is reached. The iterator is going to look up
|
||||
* the content one by one anyway. */
|
||||
* the content one by one, if harden-cname-follow . */
|
||||
remove_rrset("normalize: removing because too many cnames:",
|
||||
pkt, msg, prev, &rrset);
|
||||
continue;
|
||||
@@ -911,8 +911,8 @@ store_rrset(sldns_buffer* pkt, struct msg_parse* msg, struct module_env* env,
|
||||
packed_rrset_ttl_add(d, now);
|
||||
ref.key = k;
|
||||
ref.id = k->id;
|
||||
/*ignore ret: it was in the cache, ref updated */
|
||||
(void)rrset_cache_update(env->rrset_cache, &ref, env->alloc, now);
|
||||
/* if it was in the cache, ref updated */
|
||||
rrset_cache_update_unlock(env->rrset_cache, &ref, env->alloc, now);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -1039,6 +1039,8 @@ scrub_sanitize(sldns_buffer* pkt, struct msg_parse* msg,
|
||||
uint8_t* ns_rrset_dname = NULL;
|
||||
int added_rrlen_ede = 0;
|
||||
struct rrset_parse* rrset, *prev;
|
||||
uint8_t* sname = qinfo->qname;
|
||||
size_t snamelen = qinfo->qname_len;
|
||||
prev = NULL;
|
||||
rrset = msg->rrset_first;
|
||||
|
||||
@@ -1046,6 +1048,7 @@ scrub_sanitize(sldns_buffer* pkt, struct msg_parse* msg,
|
||||
* it can be used from the cache. After normalization, an initial
|
||||
* DNAME will have a correctly synthesized CNAME after it. */
|
||||
if(rrset && rrset->type == LDNS_RR_TYPE_DNAME &&
|
||||
env->cfg->harden_cname_follow /* CNAME chain is cut off, one DNAME is allowed here. */ &&
|
||||
rrset->section == LDNS_SECTION_ANSWER &&
|
||||
pkt_strict_sub(pkt, qinfo->qname, rrset->dname) &&
|
||||
pkt_sub(pkt, rrset->dname, zonename)) {
|
||||
@@ -1061,12 +1064,33 @@ scrub_sanitize(sldns_buffer* pkt, struct msg_parse* msg,
|
||||
* ANY queries get query name in answer section.
|
||||
* Remainders of CNAME chains are cut off and resolved by iterator. */
|
||||
while(rrset && rrset->section == LDNS_SECTION_ANSWER) {
|
||||
if(dname_pkt_compare(pkt, qinfo->qname, rrset->dname) != 0) {
|
||||
if(!env->cfg->harden_cname_follow /* CNAME chain is allowed to stay */ &&
|
||||
rrset->type == LDNS_RR_TYPE_DNAME &&
|
||||
pkt_strict_sub(pkt, sname, rrset->dname) &&
|
||||
pkt_sub(pkt, rrset->dname, zonename)) {
|
||||
/* This DNAME is allowed to stay, the synthesized
|
||||
* CNAME follows next. */
|
||||
prev = rrset;
|
||||
rrset = rrset->rrset_all_next;
|
||||
continue;
|
||||
}
|
||||
if(dname_pkt_compare(pkt, sname, rrset->dname) != 0) {
|
||||
if(has_additional(rrset->type)) del_addi = 1;
|
||||
remove_rrset("sanitize: removing extraneous answer "
|
||||
"RRset:", pkt, msg, prev, &rrset);
|
||||
continue;
|
||||
}
|
||||
if(!env->cfg->harden_cname_follow /* CNAME chain is allowed to stay */ &&
|
||||
qinfo->qtype != LDNS_RR_TYPE_ANY &&
|
||||
rrset->type == LDNS_RR_TYPE_CNAME &&
|
||||
dname_pkt_compare(pkt, sname, rrset->dname) == 0) {
|
||||
/* Follow the CNAME chain, and allow the elements
|
||||
* that match the CNAME chain. Also allow a DNAME
|
||||
* in front. */
|
||||
if(!parse_get_cname_target(rrset, &sname, &snamelen,
|
||||
pkt))
|
||||
return 0;
|
||||
}
|
||||
prev = rrset;
|
||||
rrset = rrset->rrset_all_next;
|
||||
}
|
||||
|
||||
+27
-2
@@ -1215,8 +1215,8 @@ iter_store_parentside_rrset(struct module_env* env,
|
||||
rrset->entry.hash = rrset_key_hash(&rrset->rk);
|
||||
ref.key = rrset;
|
||||
ref.id = rrset->id;
|
||||
/* ignore ret: if it was in the cache, ref updated */
|
||||
(void)rrset_cache_update(env->rrset_cache, &ref, env->alloc, *env->now);
|
||||
/* if it was in the cache, ref updated */
|
||||
rrset_cache_update_unlock(env->rrset_cache, &ref, env->alloc, *env->now);
|
||||
}
|
||||
|
||||
/** fetch NS record from reply, if any */
|
||||
@@ -1712,3 +1712,28 @@ deleg_port_number(struct module_env* env)
|
||||
return env->cfg->ssl_port;
|
||||
return -1;
|
||||
}
|
||||
|
||||
void
|
||||
shorten_answer_cname(struct reply_info* rep, uint8_t* cutoff)
|
||||
{
|
||||
size_t i, found = 0, removenum;
|
||||
uint8_t* sname = NULL;
|
||||
size_t snamelen = 0;
|
||||
for(i=0; i<rep->an_numrrsets; i++) {
|
||||
if(query_dname_compare(rep->rrsets[i]->rk.dname, cutoff) == 0) {
|
||||
found = 1;
|
||||
removenum = i;
|
||||
break;
|
||||
}
|
||||
if(ntohs(rep->rrsets[i]->rk.type) == LDNS_RR_TYPE_CNAME) {
|
||||
get_cname_target(rep->rrsets[i], &sname, &snamelen);
|
||||
if(query_dname_compare(sname, cutoff) == 0) {
|
||||
found = 1;
|
||||
removenum = i+1;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
if(!found) return; /* not found */
|
||||
val_reply_remove_answers(rep, removenum, rep->an_numrrsets-removenum);
|
||||
}
|
||||
|
||||
@@ -486,4 +486,7 @@ void iter_make_minimal(struct reply_info* rep);
|
||||
/** See if we need a different port number */
|
||||
int deleg_port_number(struct module_env* env);
|
||||
|
||||
/** Shorten reply CNAME chain to cutoff, cutoff is excluded. */
|
||||
void shorten_answer_cname(struct reply_info* rep, uint8_t* cutoff);
|
||||
|
||||
#endif /* ITERATOR_ITER_UTILS_H */
|
||||
|
||||
+68
-5
@@ -3189,7 +3189,7 @@ processQueryResponse(struct module_qstate* qstate, struct iter_qstate* iq,
|
||||
type = response_type_from_server(
|
||||
(int)((iq->chase_flags&BIT_RD) || iq->chase_to_rd),
|
||||
iq->response, &iq->qinfo_out, iq->dp, &iq->empty_nodata_found,
|
||||
iq->msg_lame_empty, iq->msg_lame_referral);
|
||||
iq->msg_lame_empty, iq->msg_lame_referral, qstate->env->cfg);
|
||||
iq->chase_to_rd = 0;
|
||||
/* remove TC flag, if this is erroneously set by TCP upstream */
|
||||
iq->response->rep->flags &= ~BIT_TC;
|
||||
@@ -3302,6 +3302,47 @@ processQueryResponse(struct module_qstate* qstate, struct iter_qstate* iq,
|
||||
* to send another query with a new qtype. */
|
||||
type = RESPONSE_TYPE_ANSWER;
|
||||
}
|
||||
if(type == RESPONSE_TYPE_ANSWER &&
|
||||
!qstate->env->cfg->harden_cname_follow /* cname chain from upstream is allowed */ &&
|
||||
qstate->env->auth_zones &&
|
||||
/* Check for CNAMEs in answer and RPZ after the CNAME. */
|
||||
reply_find_rrset_section_an(
|
||||
iq->response->rep, iq->qchase.qname,
|
||||
iq->qchase.qname_len, LDNS_RR_TYPE_CNAME,
|
||||
iq->qchase.qclass) != NULL) {
|
||||
/* If this is an answer with CNAMEs in front, and
|
||||
* RPZ wants to modify after CNAME(s), cut off, the
|
||||
* remainder, and treat as the CNAME response */
|
||||
size_t i;
|
||||
uint8_t* origname = iq->qchase.qname;
|
||||
size_t orignamelen = iq->qchase.qname_len;
|
||||
for(i=0; i<iq->response->rep->an_numrrsets; i++) {
|
||||
struct dns_msg* forged_response;
|
||||
if(ntohs(iq->response->rep->rrsets[i]->rk.type) ==
|
||||
LDNS_RR_TYPE_DNAME) {
|
||||
continue;
|
||||
}
|
||||
if(ntohs(iq->response->rep->rrsets[i]->rk.type) !=
|
||||
LDNS_RR_TYPE_CNAME) {
|
||||
break;
|
||||
}
|
||||
get_cname_target(iq->response->rep->rrsets[i],
|
||||
&iq->qchase.qname, &iq->qchase.qname_len);
|
||||
forged_response = rpz_callback_from_iterator_cname(qstate, iq);
|
||||
if(forged_response) {
|
||||
/* Cut off the answer section at this point.
|
||||
* RPZ is going to make an answer, in the
|
||||
* processInit after the CNAME(s) in front
|
||||
* are handled. */
|
||||
shorten_answer_cname(iq->response->rep,
|
||||
iq->qchase.qname);
|
||||
type = RESPONSE_TYPE_CNAME;
|
||||
break;
|
||||
}
|
||||
}
|
||||
iq->qchase.qname = origname;
|
||||
iq->qchase.qname_len = orignamelen;
|
||||
}
|
||||
|
||||
/* handle each of the type cases */
|
||||
if(type == RESPONSE_TYPE_ANSWER) {
|
||||
@@ -3804,7 +3845,7 @@ processPrimeResponse(struct module_qstate* qstate, int id)
|
||||
type = response_type_from_server(
|
||||
(int)((iq->chase_flags&BIT_RD) || iq->chase_to_rd),
|
||||
iq->response, &iq->qchase, iq->dp, NULL, iq->msg_lame_empty,
|
||||
iq->msg_lame_referral);
|
||||
iq->msg_lame_referral, qstate->env->cfg);
|
||||
if(type == RESPONSE_TYPE_ANSWER) {
|
||||
qstate->return_rcode = LDNS_RCODE_NOERROR;
|
||||
qstate->return_msg = iq->response;
|
||||
@@ -3954,15 +3995,32 @@ processDSNSResponse(struct module_qstate* qstate, int id,
|
||||
struct module_qstate* forq)
|
||||
{
|
||||
struct iter_qstate* foriq = (struct iter_qstate*)forq->minfo[id];
|
||||
int sec_an = 0, sec_ns = 0;
|
||||
|
||||
/* if the finished (iq->response) query has no NS set: continue
|
||||
* up to look for the right dp; nothing to change, do DPNSstate */
|
||||
if(qstate->return_rcode != LDNS_RCODE_NOERROR)
|
||||
return; /* seek further */
|
||||
/* find the NS RRset (without allowing CNAMEs) */
|
||||
if(!reply_find_rrset(qstate->return_msg->rep, qstate->qinfo.qname,
|
||||
qstate->qinfo.qname_len, LDNS_RR_TYPE_NS,
|
||||
qstate->qinfo.qclass)){
|
||||
/* Usually, the response has a NS in the answer section, since that
|
||||
* was the query type. And it is then the child side part of the NS
|
||||
* set. This child side part would be used if next up a delegation
|
||||
* point was constructed from cache, for example. But now it uses that
|
||||
* child side part for constructing a delegation point for the DS
|
||||
* lookup.
|
||||
* If that is not there, we can pick up the NS from the authority
|
||||
* section as well, like from a referral. */
|
||||
if(reply_find_rrset_section_an(qstate->return_msg->rep,
|
||||
qstate->qinfo.qname, qstate->qinfo.qname_len,
|
||||
LDNS_RR_TYPE_NS, qstate->qinfo.qclass))
|
||||
sec_an = 1;
|
||||
if(!sec_an && reply_find_rrset_section_ns(qstate->return_msg->rep,
|
||||
qstate->qinfo.qname, qstate->qinfo.qname_len,
|
||||
LDNS_RR_TYPE_NS, qstate->qinfo.qclass))
|
||||
sec_ns = 1;
|
||||
if(!sec_an && !sec_ns) {
|
||||
/* We probably hit an intermediate label, without a type NS
|
||||
* record there. To find the nameservers, it must go up more.*/
|
||||
return; /* seek further */
|
||||
}
|
||||
|
||||
@@ -3975,6 +4033,11 @@ processDSNSResponse(struct module_qstate* qstate, int id,
|
||||
errinf(qstate, "malloc failure, in DS search");
|
||||
return; /* dp==NULL in QUERYTARGETS makes SERVFAIL */
|
||||
}
|
||||
if(sec_an) {
|
||||
/* The NS is in the answer section, this is not a parent side,
|
||||
* but a child side response for it. */
|
||||
foriq->dp->has_parent_side_NS = 0;
|
||||
}
|
||||
/* success, go query the querytargets in the new dp (and go down) */
|
||||
}
|
||||
|
||||
|
||||
@@ -0,0 +1,49 @@
|
||||
/*
|
||||
* libunbound/authload.h - prototypes for auth load methods.
|
||||
*
|
||||
* Copyright (c) 2026, 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
|
||||
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
* HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED
|
||||
* TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
|
||||
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
|
||||
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
||||
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
/**
|
||||
* \file
|
||||
*
|
||||
* This file declares the methods that must be implemented to use the
|
||||
* auth load service.
|
||||
*/
|
||||
|
||||
#ifndef LIBUNBOUND_AUTHLOAD_H
|
||||
#define LIBUNBOUND_AUTHLOAD_H
|
||||
|
||||
/** The worker routine that services the auth load connection. */
|
||||
void worker_auth_load_service_cb(int fd, short bits, void* arg);
|
||||
|
||||
#endif /* LIBUNBOUND_AUTHLOAD_H */
|
||||
@@ -86,7 +86,7 @@ context_finalize(struct ub_ctx* ctx)
|
||||
return UB_NOMEM;
|
||||
if(!local_zones_apply_cfg(ctx->local_zones, cfg))
|
||||
return UB_INITFAIL;
|
||||
if(!auth_zones_apply_cfg(ctx->env->auth_zones, cfg, 1, &is_rpz,
|
||||
if(!auth_zones_apply_cfg(ctx->env->auth_zones, cfg, 1, 1, &is_rpz,
|
||||
ctx->env, &ctx->mods))
|
||||
return UB_INITFAIL;
|
||||
if(!(ctx->env->fwds = forwards_create()) ||
|
||||
|
||||
+5
-2
@@ -409,7 +409,7 @@ if [ "$DOWIN" = "yes" ]; then
|
||||
info "git clone --depth=1 --no-tags -b $GITBRANCH $GITREPO unbound"
|
||||
git clone --depth=1 --no-tags -b $GITBRANCH $GITREPO unbound || error_cleanup "git clone failed"
|
||||
cd unbound || error_cleanup "Unbound not exported correctly from git"
|
||||
rm -rf .git .travis.yml .gitattributes .github .gitignore || error_cleanup "Failed to remove .git tracking and ci information"
|
||||
rm -rf .git .gitattributes .github .gitignore || error_cleanup "Failed to remove .git tracking and ci information"
|
||||
|
||||
# on a re-configure the cache may no longer be valid...
|
||||
if test -f mingw32-config.cache; then rm mingw32-config.cache; fi
|
||||
@@ -603,11 +603,13 @@ info "git clone --depth=1 --no-tags -b $GITBRANCH $GITREPO unbound"
|
||||
git clone --depth=1 --no-tags -b $GITBRANCH $GITREPO unbound || error_cleanup "git clone failed"
|
||||
|
||||
cd unbound || error_cleanup "Unbound not exported correctly from git"
|
||||
rm -rf .git .travis.yml .gitattributes .github .gitignore || error_cleanup "Failed to remove .git tracking and ci information"
|
||||
rm -rf .git .gitattributes .github .gitignore || error_cleanup "Failed to remove .git tracking and ci information"
|
||||
|
||||
info "Adding libtool utils (libtoolize)."
|
||||
libtoolize -c --install || libtoolize -c || error_cleanup "Libtoolize failed."
|
||||
|
||||
# Turn this off, if the git repo times out for lookups.
|
||||
if test "updateconfigsub" = "false"; then
|
||||
# https://www.gnu.org/software/gettext/manual/html_node/config_002eguess.html
|
||||
info "Updating config.guess and config.sub"
|
||||
wget -O config.guess 'https://git.savannah.gnu.org/gitweb/?p=config.git;a=blob_plain;f=config.guess;hb=HEAD'
|
||||
@@ -621,6 +623,7 @@ if [ `uname -s | grep -i -c darwin` -ne 0 ]; then
|
||||
xattr -d com.apple.quarantine config.sub
|
||||
fi
|
||||
fi
|
||||
fi
|
||||
|
||||
info "Building configure script (autoreconf)."
|
||||
autoreconf -f || error_cleanup "Autoconf failed."
|
||||
|
||||
@@ -23,12 +23,15 @@ This example relies on the following functionalities:
|
||||
Registering inplace callback functions
|
||||
--------------------------------------
|
||||
|
||||
There are four types of inplace callback functions:
|
||||
There are seven types of inplace callback functions:
|
||||
|
||||
- `inplace callback reply functions`_
|
||||
- `inplace callback reply_cache functions`_
|
||||
- `inplace callback reply_local functions`_
|
||||
- `inplace callback reply_servfail functions`_
|
||||
- `inplace callback query functions`_
|
||||
- `inplace callback query_response functions`_
|
||||
- `inplace callback edns_back_parsed functions`_
|
||||
|
||||
|
||||
Inplace callback reply functions
|
||||
@@ -61,7 +64,9 @@ The callback function's prototype is the following:
|
||||
release. Current parameters:
|
||||
``repinfo``: Reply information for a communication point (comm_reply).
|
||||
|
||||
:return: True on success, False on failure.
|
||||
:return: True on success, False on failure. Failure terminates any further
|
||||
callback processing. If this module is ephemeral it is advised
|
||||
to clean up and return success instead.
|
||||
|
||||
"""
|
||||
|
||||
@@ -105,7 +110,9 @@ The callback function's prototype is the following:
|
||||
release. Current parameters:
|
||||
``repinfo``: Reply information for a communication point (comm_reply).
|
||||
|
||||
:return: True on success, False on failure.
|
||||
:return: True on success, False on failure. Failure terminates any further
|
||||
callback processing. If this module is ephemeral it is advised
|
||||
to clean up and return success instead.
|
||||
|
||||
For demonstration purposes we want to see if EDNS option 65002 is present
|
||||
and reply with a new value.
|
||||
@@ -152,7 +159,9 @@ The callback function's prototype is the following:
|
||||
release. Current parameters:
|
||||
``repinfo``: Reply information for a communication point (comm_reply).
|
||||
|
||||
:return: True on success, False on failure.
|
||||
:return: True on success, False on failure. Failure terminates any further
|
||||
callback processing. If this module is ephemeral it is advised
|
||||
to clean up and return success instead.
|
||||
|
||||
"""
|
||||
|
||||
@@ -197,7 +206,9 @@ The callback function's prototype is the following:
|
||||
release. Current parameters:
|
||||
``repinfo``: Reply information for a communication point (comm_reply).
|
||||
|
||||
:return: True on success, False on failure.
|
||||
:return: True on success, False on failure. Failure terminates any further
|
||||
callback processing. If this module is ephemeral it is advised
|
||||
to clean up and return success instead.
|
||||
|
||||
For demonstration purposes we want to reply with an empty EDNS code '65003'
|
||||
and log the IP address(es) of the client(s).
|
||||
@@ -214,6 +225,112 @@ We can register such function as:
|
||||
log_info("python: Could not register inplace callback function.")
|
||||
|
||||
|
||||
Inplace callback query functions
|
||||
................................
|
||||
|
||||
Called before sending a query to a backend server.
|
||||
|
||||
The callback function's prototype is the following:
|
||||
|
||||
.. code-block:: python
|
||||
|
||||
def inplace_query_callback(qinfo, flags, qstate, addr, zone, region, **kwargs):
|
||||
"""
|
||||
Function that will be registered as an inplace callback function.
|
||||
It will be called before sending a query to a backend server.
|
||||
|
||||
:param qinfo: query_info struct;
|
||||
:param flags: flags of the query;
|
||||
:param qstate: module qstate. opt_lists are available here;
|
||||
:param addr: struct sockaddr_storage. Address of the backend server;
|
||||
:param zone: zone name in binary;
|
||||
:param region: region to allocate temporary data. Needs to be used when we
|
||||
want to append a new option to opt_lists.
|
||||
:param **kwargs: Dictionary that may contain parameters added in a future
|
||||
release.
|
||||
|
||||
:return: True on success, False on failure. Failure terminates any further
|
||||
callback processing. If this module is ephemeral it is advised
|
||||
to clean up and return success instead.
|
||||
"""
|
||||
|
||||
.. note:: The function's name is irrelevant.
|
||||
|
||||
We can register such function as:
|
||||
|
||||
.. code-block:: python
|
||||
|
||||
if not register_inplace_cb_query(inplace_query_callback, env, id):
|
||||
log_info("python: Could not register inplace callback function.")
|
||||
|
||||
|
||||
Inplace callback query_response functions
|
||||
.........................................
|
||||
|
||||
Called after receiving a reply from a backend server.
|
||||
|
||||
The callback function's prototype is the following:
|
||||
|
||||
.. code-block:: python
|
||||
|
||||
def inplace_query_response_callback(qstate, response, **kwargs):
|
||||
"""
|
||||
Function that will be registered as an inplace callback function.
|
||||
It will be called after receiving a reply from a backend server.
|
||||
|
||||
:param qstate: module qstate. opt_lists are available here;
|
||||
:param response: struct dns_msg. The reply received from the backend server;
|
||||
:param **kwargs: Dictionary that may contain parameters added in a future
|
||||
release.
|
||||
|
||||
:return: True on success, False on failure. Failure terminates any further
|
||||
callback processing. If this module is ephemeral it is advised
|
||||
to clean up and return success instead.
|
||||
"""
|
||||
|
||||
.. note:: The function's name is irrelevant.
|
||||
|
||||
We can register such function as:
|
||||
|
||||
.. code-block:: python
|
||||
|
||||
if not register_inplace_cb_query_response(inplace_query_response_callback, env, id):
|
||||
log_info("python: Could not register inplace callback function.")
|
||||
|
||||
|
||||
Inplace callback edns_back_parsed functions
|
||||
...........................................
|
||||
|
||||
Called after EDNS is parsed on a reply from a backend server.
|
||||
|
||||
The callback function's prototype is the following:
|
||||
|
||||
.. code-block:: python
|
||||
|
||||
def inplace_edns_back_parsed_call(qstate, **kwargs):
|
||||
"""
|
||||
Function that will be registered as an inplace callback function.
|
||||
It will be called after EDNS is parsed on a reply from a backend server.
|
||||
|
||||
:param qstate: module qstate. opt_lists are available here;
|
||||
:param **kwargs: Dictionary that may contain parameters added in a future
|
||||
release.
|
||||
|
||||
:return: True on success, False on failure. Failure terminates any further
|
||||
callback processing. If this module is ephemeral it is advised
|
||||
to clean up and return success instead.
|
||||
"""
|
||||
|
||||
.. note:: The function's name is irrelevant.
|
||||
|
||||
We can register such function as:
|
||||
|
||||
.. code-block:: python
|
||||
|
||||
if not register_inplace_cb_edns_back_parsed_call(inplace_edns_back_parsed_call, env, id):
|
||||
log_info("python: Could not register inplace callback function.")
|
||||
|
||||
|
||||
Testing
|
||||
~~~~~~~
|
||||
|
||||
|
||||
@@ -95,7 +95,9 @@ def inplace_reply_callback(qinfo, qstate, rep, rcode, edns, opt_list_out,
|
||||
release. Current parameters:
|
||||
``repinfo``: Reply information for a communication point (comm_reply).
|
||||
|
||||
:return: True on success, False on failure.
|
||||
:return: True on success, False on failure. Failure terminates any further
|
||||
callback processing. If this module is ephemeral it is advised
|
||||
to clean up and return success instead.
|
||||
|
||||
"""
|
||||
log_info("python: called back while replying.")
|
||||
@@ -123,7 +125,9 @@ def inplace_cache_callback(qinfo, qstate, rep, rcode, edns, opt_list_out,
|
||||
release. Current parameters:
|
||||
``repinfo``: Reply information for a communication point (comm_reply).
|
||||
|
||||
:return: True on success, False on failure.
|
||||
:return: True on success, False on failure. Failure terminates any further
|
||||
callback processing. If this module is ephemeral it is advised
|
||||
to clean up and return success instead.
|
||||
|
||||
For demonstration purposes we want to see if EDNS option 65002 is present
|
||||
and reply with a new value.
|
||||
@@ -147,6 +151,12 @@ def inplace_cache_callback(qinfo, qstate, rep, rcode, edns, opt_list_out,
|
||||
else:
|
||||
log_info("python: *failed to add new option code 65002*")
|
||||
return False
|
||||
# If replying with another code is not crucial for operation
|
||||
# we can soft fail instead and allow further callback
|
||||
# processing by Unbound.
|
||||
# else:
|
||||
# log_info("python: *failed to add new option code 65002*")
|
||||
# return True
|
||||
break
|
||||
|
||||
return True
|
||||
@@ -173,7 +183,9 @@ def inplace_local_callback(qinfo, qstate, rep, rcode, edns, opt_list_out,
|
||||
release. Current parameters:
|
||||
``repinfo``: Reply information for a communication point (comm_reply).
|
||||
|
||||
:return: True on success, False on failure.
|
||||
:return: True on success, False on failure. Failure terminates any further
|
||||
callback processing. If this module is ephemeral it is advised
|
||||
to clean up and return success instead.
|
||||
|
||||
"""
|
||||
log_info("python: called back while replying with local data or chaos"
|
||||
@@ -203,7 +215,9 @@ def inplace_servfail_callback(qinfo, qstate, rep, rcode, edns, opt_list_out,
|
||||
release. Current parameters:
|
||||
``repinfo``: Reply information for a communication point (comm_reply).
|
||||
|
||||
:return: True on success, False on failure.
|
||||
:return: True on success, False on failure. Failure terminates any further
|
||||
callback processing. If this module is ephemeral it is advised
|
||||
to clean up and return success instead.
|
||||
|
||||
For demonstration purposes we want to reply with an empty EDNS code '65003'
|
||||
and log the IP address of the client.
|
||||
@@ -240,6 +254,10 @@ def inplace_query_callback(qinfo, flags, qstate, addr, zone, region, **kwargs):
|
||||
want to append a new option to opt_lists.
|
||||
:param **kwargs: Dictionary that may contain parameters added in a future
|
||||
release.
|
||||
|
||||
:return: True on success, False on failure. Failure terminates any further
|
||||
callback processing. If this module is ephemeral it is advised
|
||||
to clean up and return success instead.
|
||||
"""
|
||||
log_info("python: outgoing query to {}@{}".format(addr.addr, addr.port))
|
||||
return True
|
||||
@@ -254,6 +272,10 @@ def inplace_query_response_callback(qstate, response, **kwargs):
|
||||
:param response: struct dns_msg. The reply received from the backend server;
|
||||
:param **kwargs: Dictionary that may contain parameters added in a future
|
||||
release.
|
||||
|
||||
:return: True on success, False on failure. Failure terminates any further
|
||||
callback processing. If this module is ephemeral it is advised
|
||||
to clean up and return success instead.
|
||||
"""
|
||||
log_dns_msg(
|
||||
"python: incoming reply from {}{}".format(qstate.reply.addr, os.linesep),
|
||||
@@ -265,11 +287,15 @@ def inplace_query_response_callback(qstate, response, **kwargs):
|
||||
def inplace_edns_back_parsed_call(qstate, **kwargs):
|
||||
"""
|
||||
Function that will be registered as an inplace callback function.
|
||||
It will be called after EDNS is parsed on a reply from a backend server..
|
||||
It will be called after EDNS is parsed on a reply from a backend server.
|
||||
|
||||
:param qstate: module qstate. opt_lists are available here;
|
||||
:param **kwargs: Dictionary that may contain parameters added in a future
|
||||
release.
|
||||
|
||||
:return: True on success, False on failure. Failure terminates any further
|
||||
callback processing. If this module is ephemeral it is advised
|
||||
to clean up and return success instead.
|
||||
"""
|
||||
log_info("python: edns parsed")
|
||||
return True
|
||||
@@ -348,7 +374,7 @@ def inform_super(id, qstate, superqstate, qdata): return True
|
||||
|
||||
def operate(id, event, qstate, qdata):
|
||||
if (event == MODULE_EVENT_NEW) or (event == MODULE_EVENT_PASS):
|
||||
qstate.ext_state[id] = MODULE_WAIT_MODULE
|
||||
qstate.ext_state[id] = MODULE_WAIT_MODULE
|
||||
return True
|
||||
|
||||
elif event == MODULE_EVENT_MODDONE:
|
||||
|
||||
+14
-14
@@ -79,7 +79,7 @@
|
||||
i+(int)((unsigned int)name[i]) < len) {
|
||||
memmove(buf, name + i + 1, (unsigned int)name[i]);
|
||||
buf[(unsigned int)name[i]] = 0;
|
||||
PyList_SetItem(list, cnt, PyString_FromString(buf));
|
||||
PyList_SetItem(list, cnt, PyUnicode_FromString(buf));
|
||||
}
|
||||
i += ((unsigned int)name[i]) + 1;
|
||||
cnt++;
|
||||
@@ -96,7 +96,7 @@
|
||||
|
||||
list = PyList_New(len);
|
||||
for (i=0; i < len; i++) {
|
||||
PyList_SET_ITEM(list, i, PyString_FromString(array[i]));
|
||||
PyList_SET_ITEM(list, i, PyUnicode_FromString(array[i]));
|
||||
}
|
||||
return list;
|
||||
}
|
||||
@@ -207,7 +207,7 @@ struct query_info {
|
||||
char buf[LDNS_MAX_DOMAINLEN];
|
||||
buf[0] = '\0';
|
||||
dname_str((uint8_t*)PyBytes_AsString(dname), buf);
|
||||
return PyString_FromString(buf);
|
||||
return PyUnicode_FromString(buf);
|
||||
}
|
||||
%}
|
||||
|
||||
@@ -345,7 +345,7 @@ struct packed_rrset_data {
|
||||
PyObject* _get_data_rr_len(struct packed_rrset_data* d, int idx) {
|
||||
if ((d != NULL) && (idx >= 0) &&
|
||||
((size_t)idx < (d->count+d->rrsig_count)))
|
||||
return PyInt_FromLong(d->rr_len[idx]);
|
||||
return PyLong_FromLong(d->rr_len[idx]);
|
||||
return Py_None;
|
||||
}
|
||||
void _set_data_rr_ttl(struct packed_rrset_data* d, int idx, uint32_t ttl)
|
||||
@@ -357,7 +357,7 @@ struct packed_rrset_data {
|
||||
PyObject* _get_data_rr_ttl(struct packed_rrset_data* d, int idx) {
|
||||
if ((d != NULL) && (idx >= 0) &&
|
||||
((size_t)idx < (d->count+d->rrsig_count)))
|
||||
return PyInt_FromLong(d->rr_ttl[idx]);
|
||||
return PyLong_FromLong(d->rr_ttl[idx]);
|
||||
return Py_None;
|
||||
}
|
||||
PyObject* _get_data_rr_data(struct packed_rrset_data* d, int idx) {
|
||||
@@ -555,12 +555,12 @@ struct sockaddr_storage {};
|
||||
|
||||
if (ss->ss_family == AF_INET) {
|
||||
const struct sockaddr_in *sa4 = (struct sockaddr_in *)ss;
|
||||
return PyInt_FromLong(ntohs(sa4->sin_port));
|
||||
return PyLong_FromLong(ntohs(sa4->sin_port));
|
||||
}
|
||||
|
||||
if (ss->ss_family == AF_INET6) {
|
||||
const struct sockaddr_in6 *sa6 = (struct sockaddr_in6 *)ss;
|
||||
return PyInt_FromLong(ntohs(sa6->sin6_port));
|
||||
return PyLong_FromLong(ntohs(sa6->sin6_port));
|
||||
}
|
||||
|
||||
return Py_None;
|
||||
@@ -574,7 +574,7 @@ struct sockaddr_storage {};
|
||||
}
|
||||
|
||||
sa6 = (struct sockaddr_in6 *)ss;
|
||||
return PyInt_FromLong(ntohl(sa6->sin6_flowinfo));
|
||||
return PyLong_FromLong(ntohl(sa6->sin6_flowinfo));
|
||||
}
|
||||
|
||||
PyObject *_sockaddr_storage_scope_id(const struct sockaddr_storage *ss) {
|
||||
@@ -585,7 +585,7 @@ struct sockaddr_storage {};
|
||||
}
|
||||
|
||||
sa6 = (struct sockaddr_in6 *)ss;
|
||||
return PyInt_FromLong(ntohl(sa6->sin6_scope_id));
|
||||
return PyLong_FromLong(ntohl(sa6->sin6_scope_id));
|
||||
}
|
||||
%}
|
||||
|
||||
@@ -661,7 +661,7 @@ struct edns_option {
|
||||
%inline %{
|
||||
PyObject* _edns_option_opt_code_get(struct edns_option* option) {
|
||||
uint16_t opt_code = option->opt_code;
|
||||
return PyInt_FromLong(opt_code);
|
||||
return PyLong_FromLong(opt_code);
|
||||
}
|
||||
|
||||
PyObject* _edns_option_opt_data_get(struct edns_option* option) {
|
||||
@@ -1627,7 +1627,7 @@ int edns_opt_list_append(struct edns_option** list, uint16_t code, size_t len,
|
||||
}
|
||||
result = PyObject_Call(func, py_args, py_kwargs);
|
||||
if (result) {
|
||||
res = PyInt_AsLong(result);
|
||||
res = PyLong_AsLong(result);
|
||||
}
|
||||
out:
|
||||
Py_XDECREF(py_edns);
|
||||
@@ -1711,7 +1711,7 @@ out:
|
||||
}
|
||||
result = PyObject_Call(func, py_args, py_kwargs);
|
||||
if (result) {
|
||||
res = PyInt_AsLong(result);
|
||||
res = PyLong_AsLong(result);
|
||||
}
|
||||
out:
|
||||
Py_XDECREF(py_qinfo);
|
||||
@@ -1765,7 +1765,7 @@ out:
|
||||
}
|
||||
result = PyObject_Call(func, py_args, py_kwargs);
|
||||
if (result) {
|
||||
res = PyInt_AsLong(result);
|
||||
res = PyLong_AsLong(result);
|
||||
}
|
||||
out:
|
||||
Py_XDECREF(py_qstate);
|
||||
@@ -1814,7 +1814,7 @@ out:
|
||||
}
|
||||
result = PyObject_Call(func, py_args, py_kwargs);
|
||||
if (result) {
|
||||
res = PyInt_AsLong(result);
|
||||
res = PyLong_AsLong(result);
|
||||
}
|
||||
out:
|
||||
Py_XDECREF(py_qstate);
|
||||
|
||||
@@ -246,14 +246,14 @@ log_py_err(void)
|
||||
}
|
||||
|
||||
/* And it should be a string all ready to go - duplicate it. */
|
||||
if (!PyString_Check(obResult) && !PyUnicode_Check(obResult)) {
|
||||
if (!PyBytes_Check(obResult) && !PyUnicode_Check(obResult)) {
|
||||
log_err("pythonmod: cannot print exception, "
|
||||
"StringIO.getvalue() result did not String_Check"
|
||||
" or Unicode_Check");
|
||||
goto cleanup;
|
||||
}
|
||||
if(PyString_Check(obResult)) {
|
||||
result = PyString_AsString(obResult);
|
||||
if(PyBytes_Check(obResult)) {
|
||||
result = PyBytes_AsString(obResult);
|
||||
} else {
|
||||
ascstr = PyUnicode_AsASCIIString(obResult);
|
||||
result = PyBytes_AsString(ascstr);
|
||||
@@ -450,7 +450,7 @@ int pythonmod_init(struct module_env* env, int id)
|
||||
|
||||
pe->data = PyDict_New();
|
||||
/* add the script filename to the global "mod_env" for trivial access */
|
||||
fname = PyString_FromString(pe->fname);
|
||||
fname = PyUnicode_FromString(pe->fname);
|
||||
if(PyDict_SetItemString(pe->data, "script", fname) < 0) {
|
||||
log_err("pythonmod: could not add item to dictionary");
|
||||
Py_XDECREF(fname);
|
||||
|
||||
@@ -734,6 +734,7 @@ respip_data_answer(enum respip_action action,
|
||||
if(!new_rep)
|
||||
return -1;
|
||||
rp->rk.flags |= PACKED_RRSET_FIXEDTTL; /* avoid adjusting TTL */
|
||||
rp->entry.hash = rrset_key_hash(&rp->rk);
|
||||
new_rep->rrsets[rrset_id] = rp;
|
||||
|
||||
*redirect_rrsetp = rp;
|
||||
|
||||
+1985
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,311 @@
|
||||
/*
|
||||
* services/authload.h - authoritative zone load thread
|
||||
*
|
||||
* Copyright (c) 2026, 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
|
||||
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
* HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED
|
||||
* TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
|
||||
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
|
||||
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
||||
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
/**
|
||||
* \file
|
||||
*
|
||||
* This file contains the auth load thread. This loads authority zone
|
||||
* and RPZ zone information in a thread, in a separate memory structure.
|
||||
* When it is done, the information is swapped over to the running server.
|
||||
*/
|
||||
|
||||
#ifndef SERVICES_AUTHLOAD_H
|
||||
#define SERVICES_AUTHLOAD_H
|
||||
#include "util/locks.h"
|
||||
#include "util/rbtree.h"
|
||||
struct worker;
|
||||
struct daemon;
|
||||
struct auth_xfer;
|
||||
struct module_env;
|
||||
struct auth_load_task;
|
||||
struct comm_timer;
|
||||
|
||||
/**
|
||||
* General information for auth load threads. The number of active threads.
|
||||
*/
|
||||
struct auth_load_general_info {
|
||||
/** lock on this structure. It is after the auth_zones lock, and
|
||||
* after the auth_xfer locks. */
|
||||
lock_basic_type lock;
|
||||
/** The number of active auth load threads. */
|
||||
int num_auth_load_threads;
|
||||
/** The number of active downloads, zone transfers in progress.
|
||||
* These are going to need an auth load thread when done. The counter
|
||||
* is decremented when the thread and transfer have completed. */
|
||||
int num_auth_transfers;
|
||||
/** The auth zone xfer transfer wait list */
|
||||
struct auth_xfer* wait_transfer_list;
|
||||
/** The last item of the wait_transfer list. */
|
||||
struct auth_xfer* wait_transfer_last;
|
||||
/** To resume from a waiting item, the callback, at zero timeout is
|
||||
* used. That breaks out of callbacks and handles the items there.
|
||||
* If the timer is set, this is true. */
|
||||
int resume_timer_enabled;
|
||||
/** The resume timer for the wait_transfer list. */
|
||||
struct comm_timer* resume_timer;
|
||||
/** The worker env for the resume timer. It is set in the event base
|
||||
* of that worker. */
|
||||
struct module_env* resume_env;
|
||||
};
|
||||
|
||||
/**
|
||||
* The types of notifications that the auth load thread sends around.
|
||||
*/
|
||||
enum auth_load_notification_type {
|
||||
/** This is sent to make the auth load thread perform exit */
|
||||
auth_load_notification_exit
|
||||
};
|
||||
|
||||
/**
|
||||
* The auth load thread. The thread runs to load authority zone information
|
||||
* and RPZ information into memory. It loads into a copy. Then that is swapped
|
||||
* over to the running server. This keeps the server responsive while the
|
||||
* information is loaded.
|
||||
*/
|
||||
struct auth_load_thread {
|
||||
/** the thread number for the thread,
|
||||
* must be first to cast thread arg to int* in checklock code. */
|
||||
int threadnum;
|
||||
/** thread id, of the io thread */
|
||||
ub_thread_type tid;
|
||||
#ifdef HAVE_GETTID
|
||||
/** thread tid, the LWP id */
|
||||
pid_t thread_tid;
|
||||
/** if logging should include the LWP id */
|
||||
int thread_tid_log;
|
||||
#endif
|
||||
|
||||
/** communication socket pair, that sends commands */
|
||||
int commpair[2];
|
||||
/** if the thread has to quit */
|
||||
int need_to_quit;
|
||||
/** the event that listens on the worker to commpair,
|
||||
* it receives content from the auth load thread. */
|
||||
void* service_event;
|
||||
/** if the event that listens on the worker has
|
||||
* been added to the comm base. */
|
||||
int service_event_is_added;
|
||||
|
||||
/** the worker that the auth load is connected to */
|
||||
struct worker* worker;
|
||||
/** if the thread is inserted in the tree at the worker. */
|
||||
int tree_inserted;
|
||||
/** the rbtree node for the worker tree of auth load threads. */
|
||||
rbnode_type node;
|
||||
|
||||
/** The task that the thread is working on */
|
||||
struct auth_load_task* task;
|
||||
};
|
||||
|
||||
/**
|
||||
* The types of tasks that the auth load can perform.
|
||||
*/
|
||||
enum auth_load_task_type {
|
||||
AUTH_LOAD_TASK_TRANSFER,
|
||||
AUTH_LOAD_TASK_ZONEFILE_READ,
|
||||
AUTH_LOAD_TASK_ZONEFILE_WRITE,
|
||||
AUTH_LOAD_TASK_HTTPCHUNKS
|
||||
};
|
||||
|
||||
/**
|
||||
* The task for the auth load. The task can be to load a zone transfer, AXFR,
|
||||
* IXFR, from zonefile, and from a http read, from chunks.
|
||||
*/
|
||||
struct auth_load_task {
|
||||
/** The type of the task */
|
||||
enum auth_load_task_type task_type;
|
||||
/** The task is connected with this worker */
|
||||
struct worker* worker;
|
||||
|
||||
/** The zone name */
|
||||
uint8_t* name;
|
||||
/** The zone namelen */
|
||||
size_t namelen;
|
||||
/** The zone class */
|
||||
uint16_t dclass;
|
||||
|
||||
/** name of the host that the transfer comes from. */
|
||||
char* host;
|
||||
/** file part of the url that the transfer comes from, or NULL. */
|
||||
char* file;
|
||||
/** Set if the host is http transfer, if false it is AXFR or IXFR. */
|
||||
int on_http;
|
||||
/** Set if the transfer is doing IXFR */
|
||||
int on_ixfr;
|
||||
/** Set if the transfer is an IXFR but we detected an AXFR contents */
|
||||
int on_ixfr_is_axfr;
|
||||
/** The zone is an rpz zone. */
|
||||
int is_rpz;
|
||||
/** The etag if any, alloced. */
|
||||
char* etag;
|
||||
|
||||
/** Set if the ixfr failed. (So that there can be backoff to AXFR). */
|
||||
int ixfr_fail;
|
||||
|
||||
/** current serial (from SOA), if we have no zone, 0
|
||||
* This is for checking the IXFR result. */
|
||||
uint32_t serial;
|
||||
|
||||
/** the data chunks, or NULL, to process. */
|
||||
struct auth_chunk* chunks_first;
|
||||
/** last data chunk */
|
||||
struct auth_chunk* chunks_last;
|
||||
/** size of data in data chunks. */
|
||||
size_t chunks_total;
|
||||
|
||||
/** time taken for the task */
|
||||
struct timeval time_taken;
|
||||
/** time taken for the reload part of the task */
|
||||
struct timeval time_reload;
|
||||
/** memory used for the task */
|
||||
size_t mem_used;
|
||||
};
|
||||
|
||||
/**
|
||||
* Add a new task to be performed by the auth load thread.
|
||||
* It starts a thread.
|
||||
* @param xfr: zone transfer to start for.
|
||||
* @param worker: worker that is connected to the task.
|
||||
* @param etag: the etag, if any.
|
||||
* @return false on failure.
|
||||
*/
|
||||
int auth_load_add_task_xfr(struct auth_xfer* xfr, struct worker* worker,
|
||||
char* etag);
|
||||
|
||||
/**
|
||||
* Add a new task to be performed by the auth load thread.
|
||||
* It starts a thread. This writes to zonefile.
|
||||
* @param name: name of zone, wireformat.
|
||||
* @param namelen: length of name.
|
||||
* @param dclass: class of the zone.
|
||||
* @param env: the module env.
|
||||
* @param chunk_list: for writes after http, the chunk list with data.
|
||||
* @return false on failure to create the thread.
|
||||
*/
|
||||
int auth_load_add_task_write(uint8_t* name, size_t namelen, uint16_t dclass,
|
||||
struct module_env* env, struct auth_chunk* chunk_list);
|
||||
|
||||
/** See if there is a quit signal, true if so. */
|
||||
int auth_load_thread_poll_for_quit(struct auth_load_thread* thr);
|
||||
|
||||
/**
|
||||
* Create auth load info structure.
|
||||
* @return NULL on failure.
|
||||
*/
|
||||
struct auth_load_general_info* auth_load_info_create(void);
|
||||
|
||||
/**
|
||||
* Delete auth load info structure.
|
||||
* @param auth_load_info: to delete.
|
||||
*/
|
||||
void auth_load_info_delete(struct auth_load_general_info* auth_load_info);
|
||||
|
||||
/**
|
||||
* Clean up the auth load info. Removes pending timer, if that is enabled.
|
||||
* @param auth_load_info: to clean up.
|
||||
*/
|
||||
void auth_load_info_cleanup(struct auth_load_general_info* auth_load_info);
|
||||
|
||||
/**
|
||||
* Grab a new thread from the auth load count.
|
||||
* @param env: with auth_load_info with the active thread count.
|
||||
* and config file, with configured maximum.
|
||||
* @return false on failure, like too many active, true if successful.
|
||||
*/
|
||||
int auth_load_info_grab_thread(struct module_env* env);
|
||||
|
||||
/**
|
||||
* Release thread from auth load count. It is done.
|
||||
* @param env: with auth_load_info with the active thread count.
|
||||
*/
|
||||
void auth_load_info_release_thread(struct module_env* env);
|
||||
|
||||
/**
|
||||
* Grab a new transfer in progress, this is limited by the auth load count.
|
||||
* @param env: with auth_load_info with the active transfer number.
|
||||
* and config file, with configured maximum.
|
||||
* @return false on failure, like too many active, true if successful.
|
||||
*/
|
||||
int auth_load_info_grab_transfer_in_progress(struct module_env* env);
|
||||
|
||||
/**
|
||||
* Release transfer from active count. It is done.
|
||||
* @param env: with auth_load_info with the active transfer count.
|
||||
*/
|
||||
void auth_load_info_release_transfer_in_progress(struct module_env* env);
|
||||
|
||||
/**
|
||||
* Make transfer active in the in progress transfer count.
|
||||
* @param xfr: the xfr is in progress
|
||||
* @return false if not possible.
|
||||
*/
|
||||
int xfr_transfer_grab_active(struct auth_xfer* xfr);
|
||||
|
||||
/**
|
||||
* Release active transfer from in progress transfer count.
|
||||
* @param xfr: the xfr is no longer in progress.
|
||||
*/
|
||||
void xfr_transfer_release_active(struct auth_xfer* xfr);
|
||||
|
||||
/**
|
||||
* Add transfer to wait_transfer list. It can not become active right now.
|
||||
* @param xfr: the xfr is put on the wait_transfer list.
|
||||
*/
|
||||
void xfr_transfer_wait_active(struct auth_xfer* xfr);
|
||||
|
||||
/**
|
||||
* Remove xfr from wait_transfer list
|
||||
* @param xfr: the xfr is removed from the wait_transfer list.
|
||||
*/
|
||||
void xfr_transfer_remove_wait_transfer_list(struct auth_xfer* xfr);
|
||||
|
||||
/** The timer callback for the wait_transfer resume timer. */
|
||||
void auth_load_resume_timer_cb(void* arg);
|
||||
|
||||
/** Schedule pick up of waiting transfers. */
|
||||
void auth_load_schedule_waiting_pickup(struct module_env* env);
|
||||
|
||||
/** Compare auth load tree entries, in the worker auth load tree. */
|
||||
int auth_load_tree_cmp(const void* a, const void* b);
|
||||
|
||||
/** Delete tasks for the zone. The write and xfr tasks for that name, class
|
||||
* are sent a quit signal, and the thread is joined, as it exits. */
|
||||
void auth_load_del_zone_tasks(struct worker* worker, uint8_t* name,
|
||||
size_t namelen, uint16_t dclass);
|
||||
|
||||
/** Stop all the auth load threads. */
|
||||
void auth_load_stop_threads(struct daemon* daemon);
|
||||
|
||||
#endif /* SERVICES_AUTHLOAD_H */
|
||||
+648
-161
File diff suppressed because it is too large
Load Diff
+72
-2
@@ -65,6 +65,7 @@ struct auth_probe;
|
||||
struct auth_transfer;
|
||||
struct auth_master;
|
||||
struct auth_chunk;
|
||||
struct auth_load_thread;
|
||||
|
||||
/**
|
||||
* Authoritative zones, shared.
|
||||
@@ -125,6 +126,8 @@ struct auth_zone {
|
||||
int zone_expired;
|
||||
/** zone is a slave zone (it has masters) */
|
||||
int zone_is_slave;
|
||||
/** store etag */
|
||||
char etag[128];
|
||||
/** for downstream: this zone answers queries towards the downstream
|
||||
* clients */
|
||||
int for_downstream;
|
||||
@@ -150,6 +153,8 @@ struct auth_zone {
|
||||
int zonemd_callback_perform_write;
|
||||
/** chunklist to write for chunked transfer. */
|
||||
struct auth_chunk* perform_write_chunk_list;
|
||||
/** The zonemd transfer is an active transfer (for auth load info) */
|
||||
int zonemd_transfer_active;
|
||||
/** zone has been deleted */
|
||||
int zone_deleted;
|
||||
/** deletelist pointer, unused normally except during delete */
|
||||
@@ -404,6 +409,15 @@ struct auth_transfer {
|
||||
size_t chunks_total;
|
||||
/** start time of the transfer */
|
||||
struct timeval start_time;
|
||||
/** if the transfer is active and in the in progress count. */
|
||||
int active_transfer;
|
||||
/** if the transfer is on the wait_transfer list (it waits to
|
||||
* become active). */
|
||||
int on_wait_transfer_list;
|
||||
/** If on the wait_transfer list, the previous list item. */
|
||||
struct auth_xfer* wait_transfer_prev;
|
||||
/** If on the wait_transfer list, the next list item. */
|
||||
struct auth_xfer* wait_transfer_next;
|
||||
|
||||
/** list of upstream masters for this zone, from config */
|
||||
struct auth_master* masters;
|
||||
@@ -514,13 +528,15 @@ struct auth_zones* auth_zones_create(void);
|
||||
* @param az: auth zones structure
|
||||
* @param cfg: config to apply.
|
||||
* @param setup: if true, also sets up values in the auth zones structure
|
||||
* @param readauth: if true, reads zone files. False to omit zone file read,
|
||||
* for use by checkconf.
|
||||
* @param is_rpz: set to 1 if at least one RPZ zone is configured.
|
||||
* @param env: environment for offline verification.
|
||||
* @param mods: modules in environment.
|
||||
* @return false on failure.
|
||||
*/
|
||||
int auth_zones_apply_cfg(struct auth_zones* az, struct config_file* cfg,
|
||||
int setup, int* is_rpz, struct module_env* env,
|
||||
int setup, int readauth, int* is_rpz, struct module_env* env,
|
||||
struct module_stack* mods);
|
||||
|
||||
/** initial pick up of worker timeouts, ties events to worker event loop
|
||||
@@ -545,7 +561,15 @@ void auth_zones_delete(struct auth_zones* az);
|
||||
/**
|
||||
* Write auth zone data to file, in zonefile format.
|
||||
*/
|
||||
int auth_zone_write_file(struct auth_zone* z, const char* fname);
|
||||
int auth_zone_write_file(struct auth_zone* z, const char* fname,
|
||||
struct auth_load_thread* thr);
|
||||
|
||||
/** write to zonefile after zone has updated, reacquires z readlock.
|
||||
* The chunk list is freed on return.
|
||||
* If the zone is gone, chunk_list is freed (if non NULL). */
|
||||
void zone_write_after_update_reacq(uint8_t* name, size_t namelen,
|
||||
uint16_t dclass, struct module_env* env,
|
||||
struct auth_chunk* chunk_list, struct auth_load_thread* thr);
|
||||
|
||||
/**
|
||||
* Use auth zones to lookup the answer to a query.
|
||||
@@ -861,4 +885,50 @@ int chunkline_count_parens(struct sldns_buffer* buf, size_t start);
|
||||
/** Clear data in auth zone */
|
||||
void auth_zone_clear_data(struct auth_zone* z);
|
||||
|
||||
/** Get memory usage of auth zone */
|
||||
size_t auth_zone_get_mem(struct auth_zone* z);
|
||||
|
||||
/** create domain with the given name */
|
||||
struct auth_data* az_domain_create(struct auth_zone* z, uint8_t* nm,
|
||||
size_t nmlen);
|
||||
|
||||
/** helper traverse to delete zones */
|
||||
void auth_data_del(rbnode_type* n, void* arg);
|
||||
|
||||
/** Pick up xfr task from wait_transfer resumption. xfr is locked on entry,
|
||||
* unlocked at return. */
|
||||
void xfr_pick_up_transfer(struct auth_xfer* xfr, struct module_env* env);
|
||||
|
||||
/** Handle the end of an auth load task. */
|
||||
void xfr_process_load_end_transfer(struct auth_xfer* xfr,
|
||||
struct module_env* env, uint8_t status, int ixfr_fail,
|
||||
struct timeval* time_taken, struct timeval* time_reload,
|
||||
size_t mem_used, size_t chunks_total, struct auth_chunk* chunk_list);
|
||||
|
||||
/** Handle the end of an auth load task to write. */
|
||||
void auth_zone_process_load_end_write(struct module_env* env);
|
||||
|
||||
/** Log preview of http transfer */
|
||||
void xfr_http_preview(const char* file, struct auth_chunk* chunk_list);
|
||||
|
||||
/** Check syntax of first part of the http download */
|
||||
int xfr_http_syntax_check(uint8_t* name, size_t namelen, uint16_t dclass,
|
||||
const char* host, const char* file, struct auth_chunk* chunk_list,
|
||||
struct sldns_buffer* scratch_buffer);
|
||||
|
||||
/** Apply http transfer to auth_zone */
|
||||
int xfr_apply_http(uint8_t* name, size_t namelen, const char* host,
|
||||
const char* file, struct auth_chunk* chunk_list, struct auth_zone* z,
|
||||
struct sldns_buffer* scratch_buffer, char* etag,
|
||||
struct auth_load_thread* thr);
|
||||
|
||||
/** Apply IXFR transfer to auth_zone */
|
||||
int xfr_apply_ixfr(struct auth_chunk* chunk_list, uint32_t xfr_serial,
|
||||
struct auth_zone* z, struct sldns_buffer* scratch_buffer,
|
||||
struct auth_load_thread* thr);
|
||||
|
||||
/** Apply AXFR transfer to auth_zone */
|
||||
int xfr_apply_axfr(struct auth_chunk* chunk_list, struct auth_zone* z,
|
||||
struct sldns_buffer* scratch_buffer, struct auth_load_thread* thr);
|
||||
|
||||
#endif /* SERVICES_AUTHZONE_H */
|
||||
|
||||
Vendored
+6
-3
@@ -95,7 +95,8 @@ store_rrsets(struct module_env* env, struct reply_info* rep, time_t now,
|
||||
case 2: /* ref updated, cache is superior */
|
||||
if(region) {
|
||||
struct ub_packed_rrset_key* ck;
|
||||
lock_rw_rdlock(&rep->ref[i].key->entry.lock);
|
||||
/* the entry is already readlocked from the
|
||||
* check in rrset_cache_update. */
|
||||
/* if deleted rrset, do not copy it */
|
||||
if(rep->ref[i].key->id == 0 ||
|
||||
rep->ref[i].id != rep->ref[i].key->id)
|
||||
@@ -116,6 +117,8 @@ store_rrsets(struct module_env* env, struct reply_info* rep, time_t now,
|
||||
qrep->serve_expired_ttl = qrep->ttl + SERVE_EXPIRED_TTL;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
lock_rw_unlock(&rep->ref[i].key->entry.lock);
|
||||
}
|
||||
/* no break: also copy key item */
|
||||
/* the line below is matched by gcc regex and silences
|
||||
@@ -1208,9 +1211,9 @@ dns_cache_store(struct module_env* env, struct query_info* msgqinf,
|
||||
rep->rrsets[i]->entry.data, *env->now);
|
||||
ref.key = rep->rrsets[i];
|
||||
ref.id = rep->rrsets[i]->id;
|
||||
/*ignore ret: it was in the cache, ref updated */
|
||||
/* if it was in the cache, ref updated */
|
||||
/* no leeway for typeNS */
|
||||
(void)rrset_cache_update(env->rrset_cache, &ref,
|
||||
rrset_cache_update_unlock(env->rrset_cache, &ref,
|
||||
env->alloc,
|
||||
((ntohs(ref.key->rk.type)==LDNS_RR_TYPE_NS
|
||||
&& !pside) ? qstarttime:*env->now + leeway));
|
||||
|
||||
Vendored
+16
-3
@@ -239,9 +239,13 @@ rrset_cache_update(struct rrset_cache* r, struct rrset_ref* ref,
|
||||
equal, (rrset_type==LDNS_RR_TYPE_NS),
|
||||
(rrset_type==LDNS_RR_TYPE_A || rrset_type==LDNS_RR_TYPE_AAAA))) {
|
||||
/* cache is superior, return that value */
|
||||
if(equal) {
|
||||
ub_packed_rrset_parsedelete(k, alloc);
|
||||
/* return readlocked item. */
|
||||
return 2;
|
||||
}
|
||||
lock_rw_unlock(&e->lock);
|
||||
ub_packed_rrset_parsedelete(k, alloc);
|
||||
if(equal) return 2;
|
||||
return 1;
|
||||
}
|
||||
lock_rw_unlock(&e->lock);
|
||||
@@ -269,6 +273,15 @@ rrset_cache_update(struct rrset_cache* r, struct rrset_ref* ref,
|
||||
return 0;
|
||||
}
|
||||
|
||||
void rrset_cache_update_unlock(struct rrset_cache* r, struct rrset_ref* ref,
|
||||
struct alloc_cache* alloc, time_t timenow)
|
||||
{
|
||||
int ret = rrset_cache_update(r, ref, alloc, timenow);
|
||||
if(ret == 2) {
|
||||
lock_rw_unlock(&ref->key->entry.lock);
|
||||
}
|
||||
}
|
||||
|
||||
/** See if the name is a within signer authority */
|
||||
static int
|
||||
dname_subdomain_rrsig_signers(uint8_t* dname,
|
||||
@@ -333,8 +346,8 @@ void rrset_cache_update_wildcard(struct rrset_cache* rrset_cache,
|
||||
rrset->entry.hash = rrset_key_hash(&rrset->rk);
|
||||
ref.key = rrset;
|
||||
ref.id = rrset->id;
|
||||
/* ignore ret: if it was in the cache, ref updated */
|
||||
(void)rrset_cache_update(rrset_cache, &ref, alloc, timenow);
|
||||
/* if it was in the cache, ref updated */
|
||||
rrset_cache_update_unlock(rrset_cache, &ref, alloc, timenow);
|
||||
}
|
||||
|
||||
/** Grace period in seconds for TTL=0 DNAME rrsets (RFC 2308: do not cache).
|
||||
|
||||
Vendored
+6
@@ -129,10 +129,16 @@ void rrset_cache_touch(struct rrset_cache* r, struct ub_packed_rrset_key* key,
|
||||
* 1: reference updated, item is inserted in cache.
|
||||
* 2: reference updated, item in cache is considered superior.
|
||||
* also the rdata is equal (but other parameters in cache are superior).
|
||||
* In case 2 the item is returned under a readlock. The caller must
|
||||
* unlock.
|
||||
*/
|
||||
int rrset_cache_update(struct rrset_cache* r, struct rrset_ref* ref,
|
||||
struct alloc_cache* alloc, time_t timenow);
|
||||
|
||||
/** The rrset_cache_update routine that unlocks at end */
|
||||
void rrset_cache_update_unlock(struct rrset_cache* r, struct rrset_ref* ref,
|
||||
struct alloc_cache* alloc, time_t timenow);
|
||||
|
||||
/**
|
||||
* Update or add an rrset in the rrset cache using a wildcard dname.
|
||||
* Generates wildcard dname by prepending the wildcard label to the closest
|
||||
|
||||
@@ -1341,13 +1341,33 @@ ports_create_if(const char* ifname, int do_auto, int do_udp, int do_tcp,
|
||||
if((is_doq) && !(is_https || is_ssl)) do_tcp = 0;
|
||||
|
||||
if(do_auto) {
|
||||
enum listen_type auto_port_type;
|
||||
ub_sock = calloc(1, sizeof(struct unbound_socket));
|
||||
if(!ub_sock)
|
||||
return 0;
|
||||
if(is_dnscrypt) {
|
||||
auto_port_type = listen_type_udpancil_dnscrypt;
|
||||
add = "udpancil_dnscrypt";
|
||||
} else if(is_doq) {
|
||||
auto_port_type = listen_type_doq;
|
||||
add = "doq";
|
||||
if(if_listens_on(ifname, port, 53, NULL)) {
|
||||
log_err("DNS over QUIC is strictly not "
|
||||
"allowed on port 53 as per RFC 9250. "
|
||||
"Port 53 is for DNS datagrams. Error "
|
||||
"for interface '%s'.", ifname);
|
||||
free(ub_sock->addr);
|
||||
free(ub_sock);
|
||||
return 0;
|
||||
}
|
||||
} else {
|
||||
auto_port_type = listen_type_udpancil;
|
||||
add = "udpancil";
|
||||
}
|
||||
if((s = make_sock_port(SOCK_DGRAM, ifname, port, hints, 1,
|
||||
&noip6, rcv, snd, reuseport, transparent,
|
||||
tcp_mss, nodelay, freebind, use_systemd, dscp, ub_sock,
|
||||
(is_dnscrypt?"udpancil_dnscrypt":"udpancil"))) == -1) {
|
||||
add)) == -1) {
|
||||
free(ub_sock->addr);
|
||||
free(ub_sock);
|
||||
if(noip6) {
|
||||
@@ -1366,9 +1386,7 @@ ports_create_if(const char* ifname, int do_auto, int do_udp, int do_tcp,
|
||||
if (sock_queue_timeout && !set_recvtimestamp(s)) {
|
||||
log_warn("socket timestamping is not available");
|
||||
}
|
||||
if(!port_insert(list, s, is_dnscrypt
|
||||
?listen_type_udpancil_dnscrypt:listen_type_udpancil,
|
||||
is_pp2, ub_sock)) {
|
||||
if(!port_insert(list, s, auto_port_type, is_pp2, ub_sock)) {
|
||||
sock_close(s);
|
||||
free(ub_sock->addr);
|
||||
free(ub_sock);
|
||||
|
||||
@@ -198,7 +198,7 @@ parse_dname(const char* str, uint8_t** res, size_t* len, int* labs)
|
||||
}
|
||||
|
||||
/** create a new localzone */
|
||||
static struct local_zone*
|
||||
struct local_zone*
|
||||
local_zone_create(uint8_t* nm, size_t len, int labs,
|
||||
enum localzone_type t, uint16_t dclass)
|
||||
{
|
||||
@@ -534,7 +534,7 @@ lz_find_create_node(struct local_zone* z, uint8_t* nm, size_t nmlen,
|
||||
* 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
|
||||
int
|
||||
lz_mark_soa_for_zone(struct local_zone* z, struct ub_packed_rrset_key* soa_rrset,
|
||||
uint8_t* rdata, size_t rdata_len, time_t ttl, const char* rrstr)
|
||||
{
|
||||
|
||||
@@ -688,4 +688,14 @@ lz_enter_zone(struct local_zones* zones, const char* name, const char* type,
|
||||
*/
|
||||
void
|
||||
lz_init_parents(struct local_zones* zones);
|
||||
|
||||
/** create a new localzone */
|
||||
struct local_zone* local_zone_create(uint8_t* nm, size_t len, int labs,
|
||||
enum localzone_type t, uint16_t dclass);
|
||||
|
||||
/** Mark the SOA record for the zone. */
|
||||
int lz_mark_soa_for_zone(struct local_zone* z,
|
||||
struct ub_packed_rrset_key* soa_rrset, uint8_t* rdata,
|
||||
size_t rdata_len, time_t ttl, const char* rrstr);
|
||||
|
||||
#endif /* SERVICES_LOCALZONE_H */
|
||||
|
||||
@@ -3945,11 +3945,15 @@ setup_http_user_agent(sldns_buffer* buf, struct config_file* cfg)
|
||||
/** setup http request headers in buffer for sending query to destination */
|
||||
static int
|
||||
setup_http_request(sldns_buffer* buf, char* host, char* path,
|
||||
struct config_file* cfg)
|
||||
struct config_file* cfg, const char* etag)
|
||||
{
|
||||
sldns_buffer_clear(buf);
|
||||
sldns_buffer_printf(buf, "GET /%s HTTP/1.1\r\n", path);
|
||||
sldns_buffer_printf(buf, "Host: %s\r\n", host);
|
||||
if (etag) {
|
||||
verbose(VERB_ALGO, "sending along ETag %s in http request", etag);
|
||||
sldns_buffer_printf(buf, "If-None-Match: %s\r\n", etag);
|
||||
}
|
||||
setup_http_user_agent(buf, cfg);
|
||||
/* We do not really do multiple queries per connection,
|
||||
* but this header setting is also not needed.
|
||||
@@ -3966,7 +3970,7 @@ struct comm_point*
|
||||
outnet_comm_point_for_http(struct outside_network* outnet,
|
||||
comm_point_callback_type* cb, void* cb_arg,
|
||||
struct sockaddr_storage* to_addr, socklen_t to_addrlen, int timeout,
|
||||
int ssl, char* host, char* path, struct config_file* cfg)
|
||||
int ssl, char* host, char* path, struct config_file* cfg, char* etag)
|
||||
{
|
||||
/* cp calls cb with err=NETEVENT_DONE when transfer is done */
|
||||
struct comm_point* cp;
|
||||
@@ -4004,7 +4008,7 @@ outnet_comm_point_for_http(struct outside_network* outnet,
|
||||
comm_point_start_listening(cp, fd, timeout);
|
||||
|
||||
/* setup http request in cp->buffer */
|
||||
if(!setup_http_request(cp->buffer, host, path, cfg)) {
|
||||
if(!setup_http_request(cp->buffer, host, path, cfg, etag)) {
|
||||
log_err("error setting up http request");
|
||||
comm_point_delete(cp);
|
||||
return NULL;
|
||||
|
||||
@@ -854,7 +854,7 @@ struct comm_point* outnet_comm_point_for_tcp(struct outside_network* outnet,
|
||||
struct comm_point* outnet_comm_point_for_http(struct outside_network* outnet,
|
||||
comm_point_callback_type* cb, void* cb_arg,
|
||||
struct sockaddr_storage* to_addr, socklen_t to_addrlen, int timeout,
|
||||
int ssl, char* host, char* path, struct config_file* cfg);
|
||||
int ssl, char* host, char* path, struct config_file* cfg, char* etag);
|
||||
|
||||
/** connect tcp connection to addr, 0 on failure */
|
||||
int outnet_tcp_connect(int s, struct sockaddr_storage* addr, socklen_t addrlen);
|
||||
|
||||
+79
-33
@@ -506,24 +506,37 @@ delete_cname_override(struct rpz* r)
|
||||
static int
|
||||
rpz_apply_cfg_elements(struct rpz* r, struct config_auth* p)
|
||||
{
|
||||
enum rpz_action action_override;
|
||||
if(p->rpz_taglist && p->rpz_taglistlen) {
|
||||
r->taglistlen = p->rpz_taglistlen;
|
||||
r->taglist = memdup(p->rpz_taglist, r->taglistlen);
|
||||
if(!r->taglist) {
|
||||
uint8_t* taglist = memdup(p->rpz_taglist, p->rpz_taglistlen);
|
||||
if(!taglist) {
|
||||
log_err("malloc failure on RPZ taglist alloc");
|
||||
return 0;
|
||||
}
|
||||
if(r->taglist)
|
||||
free(r->taglist);
|
||||
r->taglist = taglist;
|
||||
r->taglistlen = p->rpz_taglistlen;
|
||||
} else {
|
||||
/* free taglist, if any */
|
||||
if(r->taglist) {
|
||||
free(r->taglist);
|
||||
r->taglist = NULL;
|
||||
r->taglistlen = 0;
|
||||
}
|
||||
}
|
||||
|
||||
if(p->rpz_action_override) {
|
||||
r->action_override = rpz_config_to_action(p->rpz_action_override);
|
||||
action_override = rpz_config_to_action(p->rpz_action_override);
|
||||
}
|
||||
else
|
||||
r->action_override = RPZ_NO_OVERRIDE_ACTION;
|
||||
action_override = RPZ_NO_OVERRIDE_ACTION;
|
||||
|
||||
if(r->action_override == RPZ_CNAME_OVERRIDE_ACTION) {
|
||||
if(action_override == RPZ_CNAME_OVERRIDE_ACTION) {
|
||||
uint8_t nm[LDNS_MAX_DOMAINLEN+1];
|
||||
size_t nmlen = sizeof(nm);
|
||||
struct regional* newr;
|
||||
struct ub_packed_rrset_key* cname_override;
|
||||
|
||||
if(!p->rpz_cname) {
|
||||
log_err("rpz: override with cname action found, but no "
|
||||
@@ -536,33 +549,50 @@ rpz_apply_cfg_elements(struct rpz* r, struct config_auth* p)
|
||||
p->rpz_cname);
|
||||
return 0;
|
||||
}
|
||||
r->cname_override = new_cname_override(r->region, nm, nmlen);
|
||||
if(!r->cname_override) {
|
||||
newr = regional_create_custom(sizeof(struct regional));
|
||||
if(!newr) {
|
||||
log_err("malloc failure on RPZ cname override region");
|
||||
return 0;
|
||||
}
|
||||
cname_override = new_cname_override(newr, nm, nmlen);
|
||||
if(!cname_override) {
|
||||
regional_destroy(newr);
|
||||
return 0;
|
||||
}
|
||||
regional_destroy(r->region);
|
||||
r->region = newr;
|
||||
r->cname_override = cname_override;
|
||||
} else {
|
||||
delete_cname_override(r);
|
||||
}
|
||||
r->action_override = action_override;
|
||||
r->log = p->rpz_log;
|
||||
r->signal_nxdomain_ra = p->rpz_signal_nxdomain_ra;
|
||||
if(p->rpz_log_name) {
|
||||
if(!(r->log_name = strdup(p->rpz_log_name))) {
|
||||
char* log_name = strdup(p->rpz_log_name);
|
||||
if(!log_name) {
|
||||
log_err("malloc failure on RPZ log_name strdup");
|
||||
return 0;
|
||||
}
|
||||
if(r->log_name)
|
||||
free(r->log_name);
|
||||
r->log_name = log_name;
|
||||
} else {
|
||||
/* free logname, if any */
|
||||
if(r->log_name) {
|
||||
free(r->log_name);
|
||||
r->log_name = NULL;
|
||||
}
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
struct rpz*
|
||||
rpz_create(struct config_auth* p)
|
||||
rpz_create_empty(void)
|
||||
{
|
||||
struct rpz* r = calloc(1, sizeof(*r));
|
||||
if(!r)
|
||||
goto err;
|
||||
|
||||
r->region = regional_create_custom(sizeof(struct regional));
|
||||
if(!r->region) {
|
||||
goto err;
|
||||
}
|
||||
return NULL;
|
||||
|
||||
if(!(r->local_zones = local_zones_create())){
|
||||
goto err;
|
||||
@@ -586,6 +616,35 @@ rpz_create(struct config_auth* p)
|
||||
if(r->ns_set == NULL) {
|
||||
goto err;
|
||||
}
|
||||
return r;
|
||||
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);
|
||||
free(r);
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
struct rpz*
|
||||
rpz_create(struct config_auth* p)
|
||||
{
|
||||
struct rpz* r = rpz_create_empty();
|
||||
if(!r)
|
||||
goto err;
|
||||
|
||||
r->region = regional_create_custom(sizeof(struct regional));
|
||||
if(!r->region) {
|
||||
goto err;
|
||||
}
|
||||
|
||||
if(!rpz_apply_cfg_elements(r, p))
|
||||
goto err;
|
||||
@@ -616,22 +675,6 @@ rpz_config(struct rpz* r, struct config_auth* p)
|
||||
{
|
||||
/* If the zonefile changes, it is read later, after which
|
||||
* rpz_clear and rpz_finish_config is called. */
|
||||
|
||||
/* free taglist, if any */
|
||||
if(r->taglist) {
|
||||
free(r->taglist);
|
||||
r->taglist = NULL;
|
||||
r->taglistlen = 0;
|
||||
}
|
||||
|
||||
/* free logname, if any */
|
||||
if(r->log_name) {
|
||||
free(r->log_name);
|
||||
r->log_name = NULL;
|
||||
}
|
||||
|
||||
delete_cname_override(r);
|
||||
|
||||
if(!rpz_apply_cfg_elements(r, p))
|
||||
return 0;
|
||||
return 1;
|
||||
@@ -2078,6 +2121,7 @@ rpz_synthesize_localdata_from_rrset(struct rpz* ATTR_UNUSED(r), struct module_qs
|
||||
* actual data. So that the actual network data and fake data
|
||||
* are kept track of separately. */
|
||||
rp->rk.flags |= PACKED_RRSET_RPZ;
|
||||
rp->entry.hash = rrset_key_hash(&rp->rk);
|
||||
new_reply_info->rrsets[0] = rp;
|
||||
msg->rep = new_reply_info;
|
||||
if(!rpz_add_soa(msg->rep, ms, az))
|
||||
@@ -2243,6 +2287,7 @@ rpz_synthesize_cname_override_msg(struct rpz* r, struct module_qstate* ms,
|
||||
* actual data. So that the actual network data and fake data
|
||||
* are kept track of separately. */
|
||||
rp->rk.flags |= PACKED_RRSET_RPZ;
|
||||
rp->entry.hash = rrset_key_hash(&rp->rk);
|
||||
new_reply_info->rrsets[0] = rp;
|
||||
|
||||
msg->rep = new_reply_info;
|
||||
@@ -2849,7 +2894,8 @@ size_t rpz_get_mem(struct rpz* r)
|
||||
m += r->taglistlen;
|
||||
if(r->log_name)
|
||||
m += strlen(r->log_name) + 1;
|
||||
m += regional_get_mem(r->region);
|
||||
if(r->region)
|
||||
m += regional_get_mem(r->region);
|
||||
m += local_zones_get_mem(r->local_zones);
|
||||
m += local_zones_get_mem(r->nsdname_zones);
|
||||
m += respip_set_get_mem(r->respip_set);
|
||||
|
||||
@@ -219,6 +219,9 @@ void rpz_delete(struct rpz* r);
|
||||
*/
|
||||
int rpz_clear(struct rpz* r);
|
||||
|
||||
/** Create empty RPZ structure, useful as a proxy for entering data. */
|
||||
struct rpz* rpz_create_empty(void);
|
||||
|
||||
/**
|
||||
* Create RPZ. RPZ must be added to linked list after creation.
|
||||
* @return: the newly created RPZ
|
||||
|
||||
@@ -197,6 +197,8 @@ sldns_fget_token_l(FILE *f, char *token, const char *delim, size_t limit, int *l
|
||||
}
|
||||
*t = '\0';
|
||||
if (c == EOF) {
|
||||
if(p != 0 || quoted)
|
||||
return -1;
|
||||
return (ssize_t)i;
|
||||
}
|
||||
|
||||
|
||||
+24
-5
@@ -842,8 +842,7 @@ rrinternal_parse_rdata(sldns_buffer* strbuf, char* token, size_t token_len,
|
||||
sldns_write_uint16(rr+dname_len+8, (uint16_t)(rr_cur_len-dname_len-10));
|
||||
*rr_len = rr_cur_len;
|
||||
/* SVCB/HTTPS handling */
|
||||
if ((rr_type == LDNS_RR_TYPE_SVCB || rr_type == LDNS_RR_TYPE_HTTPS)
|
||||
&& !was_unknown_rr_format) {
|
||||
if (rr_type == LDNS_RR_TYPE_SVCB || rr_type == LDNS_RR_TYPE_HTTPS) {
|
||||
size_t rdata_len = rr_cur_len - dname_len - 10;
|
||||
uint8_t *rdata = rr+dname_len + 10;
|
||||
|
||||
@@ -875,7 +874,14 @@ rrinternal_parse_rdata(sldns_buffer* strbuf, char* token, size_t token_len,
|
||||
|
||||
rdata_len -= 1;
|
||||
rdata += 1;
|
||||
return sldns_str2wire_check_svcbparams(rdata, rdata_len);
|
||||
status = sldns_str2wire_check_svcbparams(rdata, rdata_len);
|
||||
/* For RFC3597 generic-form input, preserve unprintable records.
|
||||
* Those could have appeared due to secondary zones, and also
|
||||
* unbound writing invalid-format records out in generic form.
|
||||
* If it can be parsed, it fixes the svcparam ordering. */
|
||||
if(was_unknown_rr_format && status != LDNS_WIREPARSE_ERR_OK)
|
||||
status = LDNS_WIREPARSE_ERR_OK;
|
||||
return status;
|
||||
|
||||
}
|
||||
return LDNS_WIREPARSE_ERR_OK;
|
||||
@@ -2304,6 +2310,8 @@ int sldns_str2wire_loc_buf(const char* str, uint8_t* rd, size_t* len)
|
||||
|
||||
if (isdigit((unsigned char) *my_str)) {
|
||||
s = strtod(my_str, &my_str);
|
||||
if(s > 60.0)
|
||||
return LDNS_WIREPARSE_ERR_SYNTAX;
|
||||
}
|
||||
|
||||
/* skip blanks before northerness */
|
||||
@@ -2362,6 +2370,8 @@ north:
|
||||
|
||||
if (isdigit((unsigned char) *my_str)) {
|
||||
s = strtod(my_str, &my_str);
|
||||
if(s > 60.0)
|
||||
return LDNS_WIREPARSE_ERR_SYNTAX;
|
||||
}
|
||||
|
||||
/* skip blanks before easterness */
|
||||
@@ -2394,8 +2404,17 @@ east:
|
||||
longitude = equator - longitude;
|
||||
}
|
||||
|
||||
altitude = (uint32_t)(strtod(my_str, &my_str)*100.0 +
|
||||
10000000.0 + 0.5);
|
||||
while (isblank((unsigned char) *my_str)) {
|
||||
my_str++;
|
||||
}
|
||||
|
||||
/* altitude */
|
||||
if(!(isdigit((unsigned char) *my_str) || *my_str == '-'))
|
||||
return LDNS_WIREPARSE_ERR_SYNTAX;
|
||||
s = strtod(my_str, &my_str);
|
||||
if(s < -100000.0 || s > 42849672.95)
|
||||
return LDNS_WIREPARSE_ERR_SYNTAX;
|
||||
altitude = (uint32_t)(s*100.0 + 10000000.0 + 0.5);
|
||||
if (*my_str == 'm' || *my_str == 'M') {
|
||||
my_str++;
|
||||
}
|
||||
|
||||
@@ -90,6 +90,7 @@ usage(void)
|
||||
printf("Usage: unbound-checkconf [file]\n");
|
||||
printf(" Checks unbound configuration file for errors.\n");
|
||||
printf("file if omitted %s is used.\n", CONFIGFILE);
|
||||
printf("-a read zone files of auth-zones and RPZ.\n");
|
||||
printf("-o option print value of option to stdout.\n");
|
||||
printf("-f output full pathname with chroot applied, eg. with -o pidfile.\n");
|
||||
printf("-q quiet (suppress output on success).\n");
|
||||
@@ -1166,11 +1167,12 @@ check_hints(struct config_file* cfg)
|
||||
|
||||
/** check auth zones */
|
||||
static void
|
||||
check_auth(struct config_file* cfg)
|
||||
check_auth(struct config_file* cfg, int readauth)
|
||||
{
|
||||
int is_rpz = 0;
|
||||
struct auth_zones* az = auth_zones_create();
|
||||
if(!az || !auth_zones_apply_cfg(az, cfg, 0, &is_rpz, NULL, NULL)) {
|
||||
if(!az || !auth_zones_apply_cfg(az, cfg, 0, readauth, &is_rpz, NULL,
|
||||
NULL)) {
|
||||
fatal_exit("Could not setup authority zones");
|
||||
}
|
||||
if(is_rpz && !strstr(cfg->module_conf, "respip"))
|
||||
@@ -1180,7 +1182,8 @@ check_auth(struct config_file* cfg)
|
||||
|
||||
/** check config file */
|
||||
static void
|
||||
checkconf(const char* cfgfile, const char* opt, int final, int quiet)
|
||||
checkconf(const char* cfgfile, const char* opt, int final, int quiet,
|
||||
int readauth)
|
||||
{
|
||||
char oldwd[4096];
|
||||
struct config_file* cfg = config_create();
|
||||
@@ -1212,7 +1215,7 @@ checkconf(const char* cfgfile, const char* opt, int final, int quiet)
|
||||
#endif
|
||||
check_fwd(cfg);
|
||||
check_hints(cfg);
|
||||
check_auth(cfg);
|
||||
check_auth(cfg, readauth);
|
||||
if(!quiet) { printf("unbound-checkconf: no errors in %s\n", cfgfile); }
|
||||
config_delete(cfg);
|
||||
}
|
||||
@@ -1228,6 +1231,7 @@ int main(int argc, char* argv[])
|
||||
int c;
|
||||
int final = 0;
|
||||
int quiet = 0;
|
||||
int readauth = 0;
|
||||
const char* f;
|
||||
const char* opt = NULL;
|
||||
const char* cfgfile = CONFIGFILE;
|
||||
@@ -1240,8 +1244,11 @@ int main(int argc, char* argv[])
|
||||
cfgfile = CONFIGFILE;
|
||||
#endif /* USE_WINSOCK */
|
||||
/* parse the options */
|
||||
while( (c=getopt(argc, argv, "fhqo:")) != -1) {
|
||||
while( (c=getopt(argc, argv, "afhqo:")) != -1) {
|
||||
switch(c) {
|
||||
case 'a':
|
||||
readauth = 1;
|
||||
break;
|
||||
case 'f':
|
||||
final = 1;
|
||||
break;
|
||||
@@ -1264,7 +1271,7 @@ int main(int argc, char* argv[])
|
||||
if(argc == 1)
|
||||
f = argv[0];
|
||||
else f = cfgfile;
|
||||
checkconf(f, opt, final, quiet);
|
||||
checkconf(f, opt, final, quiet, readauth);
|
||||
checklock_stop();
|
||||
return 0;
|
||||
}
|
||||
|
||||
+40
-5
@@ -92,7 +92,9 @@ struct fake_commpoint {
|
||||
/** runtime ptr */
|
||||
struct replay_runtime* runtime;
|
||||
/** the pending entry for this commpoint (if any) */
|
||||
struct fake_pending* pending;
|
||||
uint8_t* pkt;
|
||||
/** the length of pkt */
|
||||
size_t pkt_len;
|
||||
};
|
||||
|
||||
/** Global variable: the scenario. Saved here for when event_init is done. */
|
||||
@@ -314,6 +316,29 @@ pending_list_delete(struct replay_runtime* runtime, struct fake_pending* pend)
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Remove the item from the pending list, by packet content.
|
||||
*/
|
||||
static void
|
||||
pending_list_delete_pkt(struct replay_runtime* runtime, uint8_t* pkt,
|
||||
size_t pkt_len)
|
||||
{
|
||||
struct fake_pending** prev = &runtime->pending_list;
|
||||
struct fake_pending* p = runtime->pending_list;
|
||||
|
||||
while(p) {
|
||||
if(p->pkt_len == pkt_len &&
|
||||
memcmp(pkt, p->pkt, p->pkt_len) == 0) {
|
||||
*prev = p->next;
|
||||
delete_fake_pending(p);
|
||||
return;
|
||||
}
|
||||
|
||||
prev = &p->next;
|
||||
p = p->next;
|
||||
}
|
||||
}
|
||||
|
||||
/** number of replies in entry */
|
||||
static int
|
||||
count_reply_packets(struct entry* entry)
|
||||
@@ -1488,7 +1513,12 @@ void comm_point_delete(struct comm_point* c)
|
||||
log_assert(fc->typecode == FAKE_COMMPOINT_TYPECODE);
|
||||
if(fc->type_tcp_out) {
|
||||
/* remove tcp pending, so no more callbacks to it */
|
||||
pending_list_delete(fc->runtime, fc->pending);
|
||||
if(fc->pkt)
|
||||
pending_list_delete_pkt(fc->runtime, fc->pkt, fc->pkt_len);
|
||||
}
|
||||
if(fc->pkt) {
|
||||
free(fc->pkt);
|
||||
fc->pkt = NULL;
|
||||
}
|
||||
free(c);
|
||||
}
|
||||
@@ -1825,7 +1855,6 @@ struct comm_point* outnet_comm_point_for_tcp(struct outside_network* outnet,
|
||||
fc->cb = cb;
|
||||
fc->cb_arg = cb_arg;
|
||||
fc->runtime = runtime;
|
||||
fc->pending = pend;
|
||||
|
||||
/* used by authzone transfers */
|
||||
/* create pending item */
|
||||
@@ -1866,6 +1895,9 @@ struct comm_point* outnet_comm_point_for_tcp(struct outside_network* outnet,
|
||||
pend->pkt_len = sldns_buffer_limit(pend->buffer);
|
||||
pend->pkt = memdup(sldns_buffer_begin(pend->buffer), pend->pkt_len);
|
||||
if(!pend->pkt) fatal_exit("out of memory");
|
||||
fc->pkt_len = pend->pkt_len;
|
||||
fc->pkt = memdup(pend->pkt, pend->pkt_len);
|
||||
if(!fc->pkt) fatal_exit("out of memory");
|
||||
|
||||
log_info("testbound: created fake pending for tcp_out");
|
||||
|
||||
@@ -1879,7 +1911,7 @@ struct comm_point* outnet_comm_point_for_tcp(struct outside_network* outnet,
|
||||
struct comm_point* outnet_comm_point_for_http(struct outside_network* outnet,
|
||||
comm_point_callback_type* cb, void* cb_arg,
|
||||
struct sockaddr_storage* to_addr, socklen_t to_addrlen, int timeout,
|
||||
int ssl, char* host, char* path, struct config_file* cfg)
|
||||
int ssl, char* host, char* path, struct config_file* cfg, char* etag)
|
||||
{
|
||||
struct replay_runtime* runtime = (struct replay_runtime*)
|
||||
outnet->base;
|
||||
@@ -1902,6 +1934,7 @@ struct comm_point* outnet_comm_point_for_http(struct outside_network* outnet,
|
||||
(void)host;
|
||||
(void)path;
|
||||
(void)cfg;
|
||||
(void)etag;
|
||||
|
||||
/* handle http comm point and return contents from test script */
|
||||
return (struct comm_point*)fc;
|
||||
@@ -1918,7 +1951,6 @@ int comm_point_send_udp_msg(struct comm_point *c, sldns_buffer* packet,
|
||||
log_err("malloc failure");
|
||||
return 0;
|
||||
}
|
||||
fc->pending = pend;
|
||||
/* used by authzone transfers */
|
||||
/* create pending item */
|
||||
pend->buffer = sldns_buffer_new(sldns_buffer_limit(packet) + 10);
|
||||
@@ -1957,6 +1989,9 @@ int comm_point_send_udp_msg(struct comm_point *c, sldns_buffer* packet,
|
||||
pend->pkt_len = sldns_buffer_limit(pend->buffer);
|
||||
pend->pkt = memdup(sldns_buffer_begin(pend->buffer), pend->pkt_len);
|
||||
if(!pend->pkt) fatal_exit("out of memory");
|
||||
fc->pkt_len = pend->pkt_len;
|
||||
fc->pkt = memdup(pend->pkt, pend->pkt_len);
|
||||
if(!fc->pkt) fatal_exit("out of memory");
|
||||
|
||||
log_info("testbound: created fake pending for send_udp_msg");
|
||||
|
||||
|
||||
@@ -264,6 +264,9 @@ setup_config(FILE* in, int* lineno, int* pass_argc, char* pass_argv[])
|
||||
fprintf(cfg, " pidfile: \"\"\n");
|
||||
fprintf(cfg, " val-log-level: 2\n");
|
||||
fprintf(cfg, " log-servfail: yes\n");
|
||||
/* the extra thread needs pipe communication that is not available
|
||||
* from fake_event calls. So auth-task-threads: 0 disables them. */
|
||||
fprintf(cfg, " auth-task-threads: 0\n");
|
||||
fprintf(cfg, "remote-control: control-enable: no\n");
|
||||
while(fgets(line, MAX_LINE_LEN-1, in)) {
|
||||
parse = line;
|
||||
|
||||
+7
-7
@@ -387,7 +387,7 @@ hex_buffer2wire(sldns_buffer *data_buffer)
|
||||
uint8_t *wire = (uint8_t*)malloc(MAX_PACKETLEN);
|
||||
if(!wire) error("out of memory");
|
||||
|
||||
hexbuf = (uint8_t*)malloc(MAX_PACKETLEN);
|
||||
hexbuf = (uint8_t*)malloc(MAX_PACKETLEN * 2);
|
||||
if(!hexbuf) error("out of memory");
|
||||
for (data_buf_pos = 0; data_buf_pos < sldns_buffer_position(data_buffer); data_buf_pos++) {
|
||||
c = (int) data_wire[data_buf_pos];
|
||||
@@ -402,7 +402,7 @@ hex_buffer2wire(sldns_buffer *data_buffer)
|
||||
(c >= 'a' && c <= 'f') ||
|
||||
(c >= 'A' && c <= 'F') )
|
||||
{
|
||||
if (hexbufpos >= MAX_PACKETLEN) {
|
||||
if (hexbufpos >= MAX_PACKETLEN * 2) {
|
||||
error("buffer overflow");
|
||||
free(hexbuf);
|
||||
return 0;
|
||||
@@ -422,7 +422,7 @@ hex_buffer2wire(sldns_buffer *data_buffer)
|
||||
}
|
||||
break;
|
||||
case 2:
|
||||
if (hexbufpos >= MAX_PACKETLEN) {
|
||||
if (hexbufpos >= MAX_PACKETLEN * 2) {
|
||||
error("buffer overflow");
|
||||
free(hexbuf);
|
||||
return 0;
|
||||
@@ -433,13 +433,13 @@ hex_buffer2wire(sldns_buffer *data_buffer)
|
||||
}
|
||||
}
|
||||
|
||||
if (hexbufpos >= MAX_PACKETLEN) {
|
||||
if (hexbufpos >= MAX_PACKETLEN * 2) {
|
||||
/*verbose("packet size reached\n");*/
|
||||
}
|
||||
|
||||
/* lenient mode: length must be multiple of 2 */
|
||||
if (hexbufpos % 2 != 0) {
|
||||
if (hexbufpos >= MAX_PACKETLEN) {
|
||||
if (hexbufpos >= MAX_PACKETLEN * 2) {
|
||||
error("buffer overflow");
|
||||
free(hexbuf);
|
||||
return 0;
|
||||
@@ -630,7 +630,7 @@ read_entry(FILE* in, const char* name, struct sldns_file_parse_state* pstate,
|
||||
add_section = LDNS_SECTION_ADDITIONAL;
|
||||
else error("%s line %d: bad section %s", name, pstate->lineno, parse);
|
||||
} else if(str_keyword(&parse, "HEX_ANSWER_BEGIN")) {
|
||||
hex_data_buffer = sldns_buffer_new(MAX_PACKETLEN);
|
||||
hex_data_buffer = sldns_buffer_new(MAX_PACKETLEN*2);
|
||||
reading_hex = 1;
|
||||
} else if(str_keyword(&parse, "HEX_ANSWER_END")) {
|
||||
if(!reading_hex) {
|
||||
@@ -643,7 +643,7 @@ read_entry(FILE* in, const char* name, struct sldns_file_parse_state* pstate,
|
||||
} else if(reading_hex) {
|
||||
sldns_buffer_printf(hex_data_buffer, "%s", line);
|
||||
} else if(str_keyword(&parse, "HEX_EDNSDATA_BEGIN")) {
|
||||
hex_ednsdata_buffer = sldns_buffer_new(MAX_PACKETLEN);
|
||||
hex_ednsdata_buffer = sldns_buffer_new(MAX_PACKETLEN*2);
|
||||
reading_hex_ednsdata = 1;
|
||||
} else if(str_keyword(&parse, "HEX_EDNSDATA_END")) {
|
||||
if (!reading_hex_ednsdata) {
|
||||
|
||||
+1
-1
@@ -735,7 +735,7 @@ check_read_exact(const char* name, const char* zone)
|
||||
z = authtest_addzone(az, name, fname);
|
||||
unit_assert(z);
|
||||
outf = create_tmp_file(NULL);
|
||||
if(!auth_zone_write_file(z, outf)) {
|
||||
if(!auth_zone_write_file(z, outf, NULL)) {
|
||||
fatal_exit("write file failed for %s", fname);
|
||||
}
|
||||
checkfile(fname, outf);
|
||||
|
||||
@@ -1337,6 +1337,89 @@ static void mesh_test(void)
|
||||
free(c1);
|
||||
}
|
||||
|
||||
#include "util/data/packed_rrset.h"
|
||||
#include "sldns/sbuffer.h"
|
||||
/** packed_rrset unit tests */
|
||||
static void packed_rrset_test(void)
|
||||
{
|
||||
/* packed_rr_to_string assembles the dname, type, class, ttl and
|
||||
* rdata of one rr into a buffer of 65535 bytes. Check that it
|
||||
* refuses an rr that does not fit in there, also when the caller
|
||||
* passes a dest_len that is larger than that, like the callers in
|
||||
* daemon/cachedump.c and daemon/remote.c do. Without the check it
|
||||
* writes past the end of the assembly buffer. */
|
||||
uint8_t smalldname[] = "\003www\007example\003com";
|
||||
uint8_t smallrdata[] = {0, 4, 1, 2, 3, 4};
|
||||
uint8_t maxdname[LDNS_MAX_DOMAINLEN];
|
||||
struct ub_packed_rrset_key rrk;
|
||||
struct packed_rrset_data d;
|
||||
uint8_t* rr_data[1];
|
||||
size_t rr_len[1];
|
||||
time_t rr_ttl[1];
|
||||
size_t dest_len = 65535*4+2048; /* the size daemon/cachedump.c uses */
|
||||
char* dest = (char*)malloc(dest_len);
|
||||
int i;
|
||||
|
||||
unit_show_func("util/data/packed_rrset.c", "packed_rr_to_string");
|
||||
if(!dest) fatal_exit("out of memory");
|
||||
memset(&rrk, 0, sizeof(rrk));
|
||||
memset(&d, 0, sizeof(d));
|
||||
rrk.entry.data = &d;
|
||||
rrk.rk.rrset_class = htons(LDNS_RR_CLASS_IN);
|
||||
d.count = 1;
|
||||
d.rr_len = rr_len;
|
||||
d.rr_ttl = rr_ttl;
|
||||
d.rr_data = rr_data;
|
||||
rr_ttl[0] = 3600;
|
||||
|
||||
/* an ordinary rr is printed, also with the large dest_len */
|
||||
rrk.rk.dname = smalldname;
|
||||
rrk.rk.dname_len = sizeof(smalldname);
|
||||
rrk.rk.type = htons(LDNS_RR_TYPE_A);
|
||||
rr_data[0] = smallrdata;
|
||||
rr_len[0] = sizeof(smallrdata);
|
||||
unit_assert(packed_rr_to_string(&rrk, 0, 0, dest, dest_len) == 1);
|
||||
unit_assert(strstr(dest, "1.2.3.4") != NULL);
|
||||
|
||||
/* a dname of the maximum length, 127 labels of one character */
|
||||
for(i=0; i<127; i++) {
|
||||
maxdname[i*2] = 1;
|
||||
maxdname[i*2+1] = (uint8_t)'a';
|
||||
}
|
||||
maxdname[254] = 0;
|
||||
rrk.rk.dname = maxdname;
|
||||
rrk.rk.dname_len = sizeof(maxdname);
|
||||
rrk.rk.type = htons(LDNS_RR_TYPE_TXT);
|
||||
|
||||
/* 255+2+2+4+65272 is exactly 65535, that still fits */
|
||||
rr_len[0] = 65535 - 255 - 8;
|
||||
rr_data[0] = (uint8_t*)calloc(1, rr_len[0]);
|
||||
if(!rr_data[0]) fatal_exit("out of memory");
|
||||
sldns_write_uint16(rr_data[0], (uint16_t)(rr_len[0]-2));
|
||||
unit_assert(packed_rr_to_string(&rrk, 0, 0, dest, dest_len) == 1);
|
||||
free(rr_data[0]);
|
||||
|
||||
/* one more byte of rdata does not fit and must be refused */
|
||||
rr_len[0] = 65535 - 255 - 8 + 1;
|
||||
rr_data[0] = (uint8_t*)calloc(1, rr_len[0]);
|
||||
if(!rr_data[0]) fatal_exit("out of memory");
|
||||
sldns_write_uint16(rr_data[0], (uint16_t)(rr_len[0]-2));
|
||||
unit_assert(packed_rr_to_string(&rrk, 0, 0, dest, dest_len) == 0);
|
||||
unit_assert(dest[0] == 0);
|
||||
free(rr_data[0]);
|
||||
|
||||
/* the largest rdata an rr can hold, well over the buffer */
|
||||
rr_len[0] = 2 + 65535;
|
||||
rr_data[0] = (uint8_t*)calloc(1, rr_len[0]);
|
||||
if(!rr_data[0]) fatal_exit("out of memory");
|
||||
sldns_write_uint16(rr_data[0], 65535);
|
||||
unit_assert(packed_rr_to_string(&rrk, 0, 0, dest, dest_len) == 0);
|
||||
unit_assert(dest[0] == 0);
|
||||
free(rr_data[0]);
|
||||
|
||||
free(dest);
|
||||
}
|
||||
|
||||
void unit_show_func(const char* file, const char* func)
|
||||
{
|
||||
printf("test %s:%s\n", file, func);
|
||||
@@ -1409,6 +1492,7 @@ main(int argc, char* argv[])
|
||||
zonemd_test();
|
||||
tcpreuse_test();
|
||||
msgparse_test();
|
||||
packed_rrset_test();
|
||||
edns_ede_answer_encode_test();
|
||||
localzone_test();
|
||||
mesh_test();
|
||||
|
||||
+18
@@ -0,0 +1,18 @@
|
||||
server:
|
||||
verbosity: 8
|
||||
# num-threads: 1
|
||||
interface: 127.0.0.1
|
||||
port: @PORT@
|
||||
use-syslog: no
|
||||
directory: ""
|
||||
pidfile: "unbound.pid"
|
||||
chroot: ""
|
||||
username: ""
|
||||
do-not-query-localhost: no
|
||||
auth-task-threads: 1
|
||||
auth-zone:
|
||||
name: "example.com"
|
||||
for-upstream: yes
|
||||
for-downstream: yes
|
||||
master: "127.0.0.1@@TOPORT@"
|
||||
|
||||
+16
@@ -0,0 +1,16 @@
|
||||
BaseName: auth_load
|
||||
Version: 1.0
|
||||
Description: Perform AXFR for authority zone with auth load thread
|
||||
CreationDate: Thu 2 Jul 09:35:40 CEST 2026
|
||||
Maintainer: dr. W.C.A. Wijngaards
|
||||
Category:
|
||||
Component:
|
||||
CmdDepends:
|
||||
Depends:
|
||||
Help:
|
||||
Pre: auth_load.pre
|
||||
Post: auth_load.post
|
||||
Test: auth_load.test
|
||||
AuxFiles:
|
||||
Passed:
|
||||
Failure:
|
||||
+12
@@ -0,0 +1,12 @@
|
||||
# #-- auth_load.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
|
||||
cat fwd.log
|
||||
cat unbound.log
|
||||
+39
@@ -0,0 +1,39 @@
|
||||
# #-- auth_load.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
|
||||
|
||||
PRE="../.."
|
||||
. ../common.sh
|
||||
# if no threads; exit
|
||||
if grep -e "define HAVE_PTHREAD 1" -e "define HAVE_SOLARIS_THREADS 1" -e "define HAVE_WINDOWS_THREADS 1" $PRE/config.h; then
|
||||
echo "have threads"
|
||||
else
|
||||
skip_test "no threads"
|
||||
fi
|
||||
|
||||
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 auth_load.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'/' < auth_load.conf > ub.conf
|
||||
# start unbound in the background
|
||||
$PRE/unbound -d -c ub.conf >unbound.log 2>&1 &
|
||||
#valgrind --leak-check=full --show-reachable=yes $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
|
||||
|
||||
+55
@@ -0,0 +1,55 @@
|
||||
# #-- auth_load.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 www.example.com."
|
||||
dig @127.0.0.1 -p $UNBOUND_PORT www.example.com. | tee outfile
|
||||
if grep SERVFAIL outfile; then
|
||||
echo "> try again"
|
||||
dig @127.0.0.1 -p $UNBOUND_PORT www.example.com. | tee outfile
|
||||
fi
|
||||
if grep SERVFAIL outfile; then
|
||||
echo "> try again"
|
||||
sleep 1
|
||||
dig @127.0.0.1 -p $UNBOUND_PORT www.example.com. | tee outfile
|
||||
fi
|
||||
if grep SERVFAIL outfile; then
|
||||
echo "> try again"
|
||||
sleep 1
|
||||
dig @127.0.0.1 -p $UNBOUND_PORT www.example.com. | tee outfile
|
||||
fi
|
||||
if grep SERVFAIL outfile; then
|
||||
echo "> try again"
|
||||
sleep 1
|
||||
dig @127.0.0.1 -p $UNBOUND_PORT www.example.com. | tee outfile
|
||||
fi
|
||||
if grep SERVFAIL outfile; then
|
||||
echo "> try again"
|
||||
sleep 3
|
||||
dig @127.0.0.1 -p $UNBOUND_PORT www.example.com. | tee outfile
|
||||
fi
|
||||
if grep SERVFAIL outfile; then
|
||||
echo "> try again"
|
||||
sleep 3
|
||||
dig @127.0.0.1 -p $UNBOUND_PORT www.example.com. | tee outfile
|
||||
fi
|
||||
echo "> check answer"
|
||||
if grep "1.2.3.4" outfile; then
|
||||
echo "OK"
|
||||
else
|
||||
echo "Not OK"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
if grep "auth zone example.com. details" unbound.log; then
|
||||
echo "OK"
|
||||
else
|
||||
echo "not OK"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
exit 0
|
||||
+27
@@ -0,0 +1,27 @@
|
||||
ENTRY_BEGIN
|
||||
MATCH opcode qtype qname
|
||||
ADJUST copy_id
|
||||
REPLY QR AA NOERROR
|
||||
SECTION QUESTION
|
||||
example.com. IN SOA
|
||||
SECTION ANSWER
|
||||
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. IN SOA ns.example.com. hostmaster.example.com. 1 3600 900 86400 3600
|
||||
example.com. IN NS ns.example.net.
|
||||
EXTRA_PACKET
|
||||
REPLY QR AA NOERROR
|
||||
SECTION QUESTION
|
||||
example.com. IN AXFR
|
||||
SECTION ANSWER
|
||||
www.example.com. IN A 1.2.3.4
|
||||
example.com. IN SOA ns.example.com. hostmaster.example.com. 1 3600 900 86400 3600
|
||||
ENTRY_END
|
||||
@@ -0,0 +1,3 @@
|
||||
example.com. IN SOA ns.example.com. hostmaster.example.com. 1 3600 900 86400 3600
|
||||
example.com. IN NS ns.example.net.
|
||||
www.example.com. IN A 1.2.3.4
|
||||
@@ -0,0 +1,18 @@
|
||||
server:
|
||||
verbosity: 8
|
||||
# num-threads: 1
|
||||
interface: 127.0.0.1
|
||||
port: @PORT@
|
||||
use-syslog: no
|
||||
directory: ""
|
||||
pidfile: "unbound.pid"
|
||||
chroot: ""
|
||||
username: ""
|
||||
do-not-query-localhost: no
|
||||
auth-task-threads: 1
|
||||
auth-zone:
|
||||
name: "example.com"
|
||||
for-upstream: yes
|
||||
for-downstream: yes
|
||||
url: "https://127.0.0.1:@TOPORT@/example.com.zone"
|
||||
|
||||
+16
@@ -0,0 +1,16 @@
|
||||
BaseName: auth_load_http
|
||||
Version: 1.0
|
||||
Description: Perform http transfer for authority zone with auth load thread
|
||||
CreationDate: Tue 11 Aug 16:00:00 CEST 2026
|
||||
Maintainer: dr. W.C.A. Wijngaards
|
||||
Category:
|
||||
Component:
|
||||
CmdDepends:
|
||||
Depends:
|
||||
Help:
|
||||
Pre: auth_load_http.pre
|
||||
Post: auth_load_http.post
|
||||
Test: auth_load_http.test
|
||||
AuxFiles:
|
||||
Passed:
|
||||
Failure:
|
||||
@@ -0,0 +1,12 @@
|
||||
# #-- auth_load_http.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 $UNBOUND_PID
|
||||
kill_pid $PETAL_PID
|
||||
cat petal.log
|
||||
cat unbound.log
|
||||
+40
@@ -0,0 +1,40 @@
|
||||
# #-- auth_load_http.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
|
||||
|
||||
PRE="../.."
|
||||
. ../common.sh
|
||||
# if no threads; exit
|
||||
if grep -e "define HAVE_PTHREAD 1" -e "define HAVE_SOLARIS_THREADS 1" -e "define HAVE_WINDOWS_THREADS 1" $PRE/config.h; then
|
||||
echo "have threads"
|
||||
else
|
||||
skip_test "no threads"
|
||||
fi
|
||||
|
||||
get_random_port 2
|
||||
UNBOUND_PORT=$RND_PORT
|
||||
PETAL_PORT=$(($RND_PORT + 1))
|
||||
echo "UNBOUND_PORT=$UNBOUND_PORT" >> .tpkg.var.test
|
||||
echo "PETAL_PORT=$PETAL_PORT" >> .tpkg.var.test
|
||||
|
||||
get_make
|
||||
(cd $PRE; $MAKE petal)
|
||||
|
||||
# start https daemon
|
||||
$PRE/petal -v -a "127.0.0.1" -p $PETAL_PORT >petal.log 2>&1 &
|
||||
PETAL_PID=$!
|
||||
echo "PETAL_PID=$PETAL_PID" >> .tpkg.var.test
|
||||
wait_petal_up petal.log
|
||||
|
||||
# make config file
|
||||
sed -e 's/@PORT\@/'$UNBOUND_PORT'/' -e 's/@TOPORT\@/'$PETAL_PORT'/' < auth_load_http.conf > ub.conf
|
||||
# start unbound in the background
|
||||
$PRE/unbound -d -c ub.conf >unbound.log 2>&1 &
|
||||
#valgrind --leak-check=full --show-reachable=yes $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_unbound_up unbound.log
|
||||
@@ -0,0 +1,55 @@
|
||||
# #-- auth_load_http.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 www.example.com."
|
||||
dig @127.0.0.1 -p $UNBOUND_PORT www.example.com. | tee outfile
|
||||
if grep SERVFAIL outfile; then
|
||||
echo "> try again"
|
||||
dig @127.0.0.1 -p $UNBOUND_PORT www.example.com. | tee outfile
|
||||
fi
|
||||
if grep SERVFAIL outfile; then
|
||||
echo "> try again"
|
||||
sleep 1
|
||||
dig @127.0.0.1 -p $UNBOUND_PORT www.example.com. | tee outfile
|
||||
fi
|
||||
if grep SERVFAIL outfile; then
|
||||
echo "> try again"
|
||||
sleep 1
|
||||
dig @127.0.0.1 -p $UNBOUND_PORT www.example.com. | tee outfile
|
||||
fi
|
||||
if grep SERVFAIL outfile; then
|
||||
echo "> try again"
|
||||
sleep 1
|
||||
dig @127.0.0.1 -p $UNBOUND_PORT www.example.com. | tee outfile
|
||||
fi
|
||||
if grep SERVFAIL outfile; then
|
||||
echo "> try again"
|
||||
sleep 3
|
||||
dig @127.0.0.1 -p $UNBOUND_PORT www.example.com. | tee outfile
|
||||
fi
|
||||
if grep SERVFAIL outfile; then
|
||||
echo "> try again"
|
||||
sleep 3
|
||||
dig @127.0.0.1 -p $UNBOUND_PORT www.example.com. | tee outfile
|
||||
fi
|
||||
echo "> check answer"
|
||||
if grep "1.2.3.4" outfile; then
|
||||
echo "OK"
|
||||
else
|
||||
echo "Not OK"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
if grep "auth zone example.com. details" unbound.log; then
|
||||
echo "OK"
|
||||
else
|
||||
echo "not OK"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
exit 0
|
||||
+21
@@ -0,0 +1,21 @@
|
||||
-----BEGIN RSA PRIVATE KEY-----
|
||||
MIIDfQIBAAKBwQC1xQ/Kca6zszZbcCtdOTIH2Uy2gOy/DfabMUU7TmNPm0dVE0NJ
|
||||
RuN+Rm304SonpwghfP2/ULZNnuDgpG03/32yI7k/VzG6iA4hiF7tT/KAAWC/+2l1
|
||||
QCsawCV2bSrFK0VhcZr7ALqXd8vkDaQ867K029ypjOQtAJ85qdO3mERy7TGtdUcu
|
||||
O6hLeVet419YeQ2F8cfNxn63d7bOzNGLPW5xwaCd3UcgD+Ib0k4xfFvbinvPQUeU
|
||||
J/i4YDWexFYSL+ECAwEAAQKBwCLXXQl+9O+5AEhSnd1Go1Jh0pSA7eBJOuXQcebG
|
||||
Rb7ykp+6C4G2NtDziwwPRNdI6wQQQ0sym18RfyVQHydGr78/nbiIbB3HCn5e92Mh
|
||||
mefzW6ow9Kvm2txLzGKA1lvoyRbNm81jnG/eygi3u7Nqd5PNv+4dHj2RkTlmxOeh
|
||||
qnDMVP5md8uZPv6lYNnrnIzvLCR5vnPNdVwn89AqzI85IcDZdy0R9ZX4NBbsDgAU
|
||||
6ig6uXuRXvSGiyJ/OUXSrnogaQJhAOjvkHUhVZQkPOxO90TNH4j0GdKKtbSWxIdz
|
||||
lKfuJeBAEqs0TL+C6vbS81Xw3W1alyDdUBk3rJMOBqW6Ryq5HNL+j5H+Jfsh7fvc
|
||||
Yle+5wHGci0P9zCFZCrY8It7n9XFIwJhAMfEi6oJa2G8waPJ1bQhxka82Tf9pnKM
|
||||
XCn/1BBOFjVIx5F842cpA+zp5a62GENTGYPQTTRBB/2/ZwnW5aIkrlg54AtmbqBZ
|
||||
Oh+2kJdJQD/tfoVmc5soUE2ScTHadK5RKwJhAN4w9kjkXS+MSZjX0kIMsBIBVkhh
|
||||
C+aREjJqa9ir7/Ey7RvmLXdYuCxtGLRXp7/R8+rjcK49Tx6O+IRJZe042mfhbq3C
|
||||
EhS1Tr86f4xXix9EXlDhs9bSxrOgcAN9Dv/opQJhAK7eBcPaav0rVfYh/8emqQHS
|
||||
3fJ9Pu6WnzbEksWTFS2ff9KDGCx9YspIFJ5TF/oXDAaumGZdZrlgirm6O1kr8tGY
|
||||
F97i04PZl1+bWAaWQH+1TUNI43m2WFUPE7coG2tb8QJgcddDg9VlXliZqgcETZfJ
|
||||
kJmYETxrcSn3ao6v116N8yxhEgUgjkmsCTiFgx36iDVnXwK6PIt+sIu8MC7eYNa3
|
||||
berrv/M21K0LRn20IWRxvUobG070weHCAgkko7fTWgr2
|
||||
-----END RSA PRIVATE KEY-----
|
||||
+14
@@ -0,0 +1,14 @@
|
||||
-----BEGIN CERTIFICATE-----
|
||||
MIICFzCCAUACCQDO660L5y5LGDANBgkqhkiG9w0BAQUFADAQMQ4wDAYDVQQDEwVw
|
||||
ZXRhbDAeFw0xMDA5MzAxMzQzMDFaFw0zMDA2MTcxMzQzMDFaMBAxDjAMBgNVBAMT
|
||||
BXBldGFsMIHfMA0GCSqGSIb3DQEBAQUAA4HNADCByQKBwQC1xQ/Kca6zszZbcCtd
|
||||
OTIH2Uy2gOy/DfabMUU7TmNPm0dVE0NJRuN+Rm304SonpwghfP2/ULZNnuDgpG03
|
||||
/32yI7k/VzG6iA4hiF7tT/KAAWC/+2l1QCsawCV2bSrFK0VhcZr7ALqXd8vkDaQ8
|
||||
67K029ypjOQtAJ85qdO3mERy7TGtdUcuO6hLeVet419YeQ2F8cfNxn63d7bOzNGL
|
||||
PW5xwaCd3UcgD+Ib0k4xfFvbinvPQUeUJ/i4YDWexFYSL+ECAwEAATANBgkqhkiG
|
||||
9w0BAQUFAAOBwQBBkX9KDP2RXbg+xPmdJ4P6CwvA5x1LZwC++ydVx4NlvT0pWicD
|
||||
ZUnXjcWAJlkeOuUBAqFG7WHTrXpUUAjmdqFVq2yFjteUYBdrFz0RDB2jM9feeKYO
|
||||
mTgxdZyT9a6humxCxt5VfgT02axLjm/2AqCyFPMbf4PASoJDln01AEuZLZ8Xl2gV
|
||||
bYHMnHTGoD1Hu6FNEzRgkMC6XT8X3YjHvzQhpc/qL5wEfEsinQGdX4twsuWbf8xd
|
||||
q7miNnkO8vd0maw=
|
||||
-----END CERTIFICATE-----
|
||||
@@ -0,0 +1,28 @@
|
||||
server:
|
||||
verbosity: 8
|
||||
# num-threads: 1
|
||||
interface: 127.0.0.1
|
||||
port: @PORT@
|
||||
use-syslog: no
|
||||
directory: ""
|
||||
pidfile: "unbound.pid"
|
||||
module-config: "respip validator iterator"
|
||||
chroot: ""
|
||||
username: ""
|
||||
do-not-query-localhost: no
|
||||
auth-task-threads: 1
|
||||
log-queries: yes
|
||||
log-replies: yes
|
||||
|
||||
forward-zone:
|
||||
name: "."
|
||||
forward-addr: "127.0.0.1@@TOPORT@"
|
||||
|
||||
rpz:
|
||||
name: "rpz.example.com"
|
||||
for-downstream: yes
|
||||
master: "127.0.0.1@@TOPORT@"
|
||||
allow-notify: 127.0.0.0/8
|
||||
zonefile: "auth_load_ixfr.zone"
|
||||
rpz-log: yes
|
||||
rpz-log-name: "rpz.example.com"
|
||||
+16
@@ -0,0 +1,16 @@
|
||||
BaseName: auth_load_ixfr
|
||||
Version: 1.0
|
||||
Description: Load RPZ zone with auth load thread with IXFR.
|
||||
CreationDate: Thu 15 Oct 13:00:00 CEST 2026
|
||||
Maintainer: dr. W.C.A. Wijngaards
|
||||
Category:
|
||||
Component:
|
||||
CmdDepends:
|
||||
Depends:
|
||||
Help:
|
||||
Pre: auth_load_ixfr.pre
|
||||
Post: auth_load_ixfr.post
|
||||
Test: auth_load_ixfr.test
|
||||
AuxFiles:
|
||||
Passed:
|
||||
Failure:
|
||||
@@ -0,0 +1,12 @@
|
||||
# #-- auth_load_ixfr.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
|
||||
cat fwd.log
|
||||
cat unbound.log
|
||||
+39
@@ -0,0 +1,39 @@
|
||||
# #-- auth_load_ixfr.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
|
||||
|
||||
PRE="../.."
|
||||
. ../common.sh
|
||||
# if no threads; exit
|
||||
if grep -e "define HAVE_PTHREAD 1" -e "define HAVE_SOLARIS_THREADS 1" -e "define HAVE_WINDOWS_THREADS 1" $PRE/config.h; then
|
||||
echo "have threads"
|
||||
else
|
||||
skip_test "no threads"
|
||||
fi
|
||||
|
||||
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 auth_load_ixfr.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'/' < auth_load_ixfr.conf > ub.conf
|
||||
# start unbound in the background
|
||||
$PRE/unbound -d -c ub.conf >unbound.log 2>&1 &
|
||||
#valgrind --leak-check=full --show-reachable=yes $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
|
||||
|
||||
@@ -0,0 +1,88 @@
|
||||
# #-- auth_load_ixfr.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="../.."
|
||||
. ../common.sh
|
||||
# do the test
|
||||
|
||||
$PRE/streamtcp -f 127.0.0.1@$UNBOUND_PORT rpz.example.com. NOTIFY IN
|
||||
|
||||
wait_logfile unbound.log "auth zone rpz.example.com. updated to serial 2" 10
|
||||
|
||||
# The answer is rewritten by RPZ, that is loaded in the auth load thread.
|
||||
echo "> dig www.example.com."
|
||||
dig @127.0.0.1 -p $UNBOUND_PORT www.example.com. | tee outfile
|
||||
if grep SERVFAIL outfile; then
|
||||
echo "> try again"
|
||||
dig @127.0.0.1 -p $UNBOUND_PORT www.example.com. | tee outfile
|
||||
fi
|
||||
if grep SERVFAIL outfile; then
|
||||
echo "> try again"
|
||||
sleep 1
|
||||
dig @127.0.0.1 -p $UNBOUND_PORT www.example.com. | tee outfile
|
||||
fi
|
||||
if grep SERVFAIL outfile; then
|
||||
echo "> try again"
|
||||
sleep 1
|
||||
dig @127.0.0.1 -p $UNBOUND_PORT www.example.com. | tee outfile
|
||||
fi
|
||||
if grep SERVFAIL outfile; then
|
||||
echo "> try again"
|
||||
sleep 1
|
||||
dig @127.0.0.1 -p $UNBOUND_PORT www.example.com. | tee outfile
|
||||
fi
|
||||
if grep SERVFAIL outfile; then
|
||||
echo "> try again"
|
||||
sleep 3
|
||||
dig @127.0.0.1 -p $UNBOUND_PORT www.example.com. | tee outfile
|
||||
fi
|
||||
if grep SERVFAIL outfile; then
|
||||
echo "> try again"
|
||||
sleep 3
|
||||
dig @127.0.0.1 -p $UNBOUND_PORT www.example.com. | tee outfile
|
||||
fi
|
||||
echo "> check answer"
|
||||
if grep "1.2.3.5" outfile; then
|
||||
echo "OK"
|
||||
else
|
||||
echo "Not OK"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
echo "> dig o3.example.com."
|
||||
dig @127.0.0.1 -p $UNBOUND_PORT o3.example.com. | tee outfile
|
||||
echo "> check answer"
|
||||
if grep "1.2.3.7" outfile; then
|
||||
echo "OK"
|
||||
else
|
||||
echo "Not OK"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
echo "> dig other.example.com."
|
||||
dig @127.0.0.1 -p $UNBOUND_PORT other.example.com. | tee outfile
|
||||
echo "> check answer"
|
||||
if grep "10.20.30.40" outfile; then
|
||||
echo "OK"
|
||||
else
|
||||
echo "Not OK"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
if grep "auth zone rpz.example.com. details" unbound.log; then
|
||||
echo "OK"
|
||||
else
|
||||
echo "not OK"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# wait_logfile
|
||||
wait_logfile unbound.log "write zonefile auth_load_ixfr.zone for rpz.example.com." 10
|
||||
echo ""
|
||||
echo "> auth_load_ixfr.zone"
|
||||
cat auth_load_ixfr.zone
|
||||
|
||||
exit 0
|
||||
@@ -0,0 +1,36 @@
|
||||
ENTRY_BEGIN
|
||||
MATCH opcode qtype qname
|
||||
ADJUST copy_id
|
||||
REPLY QR AA NOERROR
|
||||
SECTION QUESTION
|
||||
rpz.example.com. IN SOA
|
||||
SECTION ANSWER
|
||||
rpz.example.com. IN SOA ns.example.com. hostmaster.example.com. 2 3600 900 86400 3600
|
||||
ENTRY_END
|
||||
|
||||
ENTRY_BEGIN
|
||||
MATCH opcode qtype qname
|
||||
ADJUST copy_id
|
||||
REPLY QR AA NOERROR
|
||||
SECTION QUESTION
|
||||
rpz.example.com. IN IXFR
|
||||
SECTION ANSWER
|
||||
rpz.example.com. IN SOA ns.example.com. hostmaster.example.com. 2 3600 900 86400 3600
|
||||
rpz.example.com. IN SOA ns.example.com. hostmaster.example.com. 1 3600 900 86400 3600
|
||||
www.example.com.rpz.example.com. IN A 1.2.3.4
|
||||
other.example.com.rpz.example.com. IN A 1.2.3.5
|
||||
rpz.example.com. IN SOA ns.example.com. hostmaster.example.com. 2 3600 900 86400 3600
|
||||
www.example.com.rpz.example.com. IN A 1.2.3.5
|
||||
o3.example.com.rpz.example.com. IN A 1.2.3.7
|
||||
rpz.example.com. IN SOA ns.example.com. hostmaster.example.com. 2 3600 900 86400 3600
|
||||
ENTRY_END
|
||||
|
||||
ENTRY_BEGIN
|
||||
MATCH opcode qtype qname
|
||||
ADJUST copy_id
|
||||
REPLY QR RD RA NOERROR
|
||||
SECTION QUESTION
|
||||
other.example.com. IN A
|
||||
SECTION ANSWER
|
||||
other.example.com. IN A 10.20.30.40
|
||||
ENTRY_END
|
||||
@@ -0,0 +1,9 @@
|
||||
rpz.example.com. IN SOA ns.example.com. hostmaster.example.com. 1 3600 900 86400 3600
|
||||
rpz.example.com. IN NS ns.example.net.
|
||||
www.example.com.rpz.example.com. IN A 1.2.3.4
|
||||
other.example.com.rpz.example.com. IN A 1.2.3.5
|
||||
o2.example.com.rpz.example.com. IN A 1.2.3.6
|
||||
n.example.com.rpz.example.com IN CNAME .
|
||||
32.5.5.0.192.rpz-client-ip.rpz.example.com. A 1.2.3.5
|
||||
32.123.2.0.192.rpz-ip.rpz.example.com. A 203.0.113.123
|
||||
32.124.2.0.192.rpz-ip.rpz.example.com. CNAME .
|
||||
+103
@@ -0,0 +1,103 @@
|
||||
server:
|
||||
verbosity: 8
|
||||
num-threads: 1
|
||||
interface: 127.0.0.1
|
||||
port: @PORT@
|
||||
use-syslog: no
|
||||
directory: ""
|
||||
pidfile: "unbound.pid"
|
||||
chroot: ""
|
||||
username: ""
|
||||
do-not-query-localhost: no
|
||||
auth-task-threads: 2
|
||||
|
||||
auth-zone:
|
||||
name: "example1.com"
|
||||
for-upstream: yes
|
||||
for-downstream: yes
|
||||
master: "127.0.0.1@@TOPORT@"
|
||||
|
||||
auth-zone:
|
||||
name: "example2.com"
|
||||
for-upstream: yes
|
||||
for-downstream: yes
|
||||
master: "127.0.0.1@@TOPORT@"
|
||||
|
||||
auth-zone:
|
||||
name: "example3.com"
|
||||
for-upstream: yes
|
||||
for-downstream: yes
|
||||
master: "127.0.0.1@@TOPORT@"
|
||||
|
||||
auth-zone:
|
||||
name: "example4.com"
|
||||
for-upstream: yes
|
||||
for-downstream: yes
|
||||
master: "127.0.0.1@@TOPORT@"
|
||||
|
||||
auth-zone:
|
||||
name: "example5.com"
|
||||
for-upstream: yes
|
||||
for-downstream: yes
|
||||
master: "127.0.0.1@@TOPORT@"
|
||||
|
||||
auth-zone:
|
||||
name: "example6.com"
|
||||
for-upstream: yes
|
||||
for-downstream: yes
|
||||
master: "127.0.0.1@@TOPORT@"
|
||||
|
||||
auth-zone:
|
||||
name: "example7.com"
|
||||
for-upstream: yes
|
||||
for-downstream: yes
|
||||
master: "127.0.0.1@@TOPORT@"
|
||||
|
||||
auth-zone:
|
||||
name: "example8.com"
|
||||
for-upstream: yes
|
||||
for-downstream: yes
|
||||
master: "127.0.0.1@@TOPORT@"
|
||||
|
||||
auth-zone:
|
||||
name: "example9.com"
|
||||
for-upstream: yes
|
||||
for-downstream: yes
|
||||
master: "127.0.0.1@@TOPORT@"
|
||||
|
||||
auth-zone:
|
||||
name: "example10.com"
|
||||
for-upstream: yes
|
||||
for-downstream: yes
|
||||
master: "127.0.0.1@@TOPORT@"
|
||||
|
||||
auth-zone:
|
||||
name: "example11.com"
|
||||
for-upstream: yes
|
||||
for-downstream: yes
|
||||
master: "127.0.0.1@@TOPORT@"
|
||||
|
||||
auth-zone:
|
||||
name: "example12.com"
|
||||
for-upstream: yes
|
||||
for-downstream: yes
|
||||
master: "127.0.0.1@@TOPORT@"
|
||||
|
||||
auth-zone:
|
||||
name: "example13.com"
|
||||
for-upstream: yes
|
||||
for-downstream: yes
|
||||
master: "127.0.0.1@@TOPORT@"
|
||||
|
||||
auth-zone:
|
||||
name: "example14.com"
|
||||
for-upstream: yes
|
||||
for-downstream: yes
|
||||
master: "127.0.0.1@@TOPORT@"
|
||||
|
||||
auth-zone:
|
||||
name: "example15.com"
|
||||
for-upstream: yes
|
||||
for-downstream: yes
|
||||
master: "127.0.0.1@@TOPORT@"
|
||||
|
||||
+16
@@ -0,0 +1,16 @@
|
||||
BaseName: auth_load_list
|
||||
Version: 1.0
|
||||
Description: Perform more transfers than the auth load thread count
|
||||
CreationDate: Fri 9 Jul 15:00:00 CEST 2026
|
||||
Maintainer: dr. W.C.A. Wijngaards
|
||||
Category:
|
||||
Component:
|
||||
CmdDepends:
|
||||
Depends:
|
||||
Help:
|
||||
Pre: auth_load_list.pre
|
||||
Post: auth_load_list.post
|
||||
Test: auth_load_list.test
|
||||
AuxFiles:
|
||||
Passed:
|
||||
Failure:
|
||||
@@ -0,0 +1,12 @@
|
||||
# #-- auth_load_list.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
|
||||
cat fwd.log
|
||||
cat unbound.log
|
||||
+74
@@ -0,0 +1,74 @@
|
||||
# #-- auth_load_list.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
|
||||
|
||||
PRE="../.."
|
||||
. ../common.sh
|
||||
# if no threads; exit
|
||||
if grep -e "define HAVE_PTHREAD 1" -e "define HAVE_SOLARIS_THREADS 1" -e "define HAVE_WINDOWS_THREADS 1" $PRE/config.h; then
|
||||
echo "have threads"
|
||||
else
|
||||
skip_test "no threads"
|
||||
fi
|
||||
|
||||
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
|
||||
|
||||
# create auth_load_list.testns
|
||||
for((i=1; i<16; i++)); do
|
||||
cat >>auth_load_list.testns <<EOF
|
||||
|
||||
ENTRY_BEGIN
|
||||
MATCH opcode qtype qname
|
||||
ADJUST copy_id
|
||||
REPLY QR AA NOERROR
|
||||
SECTION QUESTION
|
||||
example$i.com. IN SOA
|
||||
SECTION ANSWER
|
||||
example$i.com. IN SOA ns.example$i.com. hostmaster.example$i.com. 1 3600 900 86400 3600
|
||||
ENTRY_END
|
||||
|
||||
ENTRY_BEGIN
|
||||
MATCH opcode qtype qname
|
||||
ADJUST copy_id
|
||||
REPLY QR AA NOERROR
|
||||
SECTION QUESTION
|
||||
example$i.com. IN AXFR
|
||||
SECTION ANSWER
|
||||
example$i.com. IN SOA ns.example$i.com. hostmaster.example$i.com. 1 3600 900 86400 3600
|
||||
example$i.com. IN NS ns.example.net.
|
||||
EXTRA_PACKET
|
||||
REPLY QR AA NOERROR
|
||||
SECTION QUESTION
|
||||
example$i.com. IN AXFR
|
||||
SECTION ANSWER
|
||||
www.example$i.com. IN A 1.2.3.4
|
||||
example$i.com. IN SOA ns.example$i.com. hostmaster.example$i.com. 1 3600 900 86400 3600
|
||||
ENTRY_END
|
||||
EOF
|
||||
done
|
||||
|
||||
get_ldns_testns
|
||||
$LDNS_TESTNS -p $FWD_PORT auth_load_list.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'/' < auth_load_list.conf > ub.conf
|
||||
# start unbound in the background
|
||||
$PRE/unbound -d -c ub.conf >unbound.log 2>&1 &
|
||||
#valgrind --leak-check=full --show-reachable=yes $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
|
||||
|
||||
@@ -0,0 +1,60 @@
|
||||
# #-- auth_load_list.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
|
||||
for i in 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15; do
|
||||
name="www.example$i.com"
|
||||
echo ""
|
||||
echo "> dig $name"
|
||||
dig @127.0.0.1 -p $UNBOUND_PORT $name | tee outfile
|
||||
if grep SERVFAIL outfile; then
|
||||
echo "> try again"
|
||||
dig @127.0.0.1 -p $UNBOUND_PORT $name | tee outfile
|
||||
fi
|
||||
if grep SERVFAIL outfile; then
|
||||
echo "> try again"
|
||||
sleep 1
|
||||
dig @127.0.0.1 -p $UNBOUND_PORT $name | tee outfile
|
||||
fi
|
||||
if grep SERVFAIL outfile; then
|
||||
echo "> try again"
|
||||
sleep 1
|
||||
dig @127.0.0.1 -p $UNBOUND_PORT $name | tee outfile
|
||||
fi
|
||||
if grep SERVFAIL outfile; then
|
||||
echo "> try again"
|
||||
sleep 1
|
||||
dig @127.0.0.1 -p $UNBOUND_PORT $name | tee outfile
|
||||
fi
|
||||
if grep SERVFAIL outfile; then
|
||||
echo "> try again"
|
||||
sleep 3
|
||||
dig @127.0.0.1 -p $UNBOUND_PORT $name | tee outfile
|
||||
fi
|
||||
if grep SERVFAIL outfile; then
|
||||
echo "> try again"
|
||||
sleep 3
|
||||
dig @127.0.0.1 -p $UNBOUND_PORT $name | tee outfile
|
||||
fi
|
||||
echo "> check answer"
|
||||
if grep "1.2.3.4" outfile; then
|
||||
echo "OK"
|
||||
else
|
||||
echo "Not OK"
|
||||
exit 1
|
||||
fi
|
||||
if grep "auth zone example$i.com. details" unbound.log; then
|
||||
echo "OK"
|
||||
else
|
||||
echo "not OK"
|
||||
exit 1
|
||||
fi
|
||||
done
|
||||
echo "loop done"
|
||||
|
||||
exit 0
|
||||
+26
@@ -0,0 +1,26 @@
|
||||
server:
|
||||
verbosity: 8
|
||||
# num-threads: 1
|
||||
interface: 127.0.0.1
|
||||
port: @PORT@
|
||||
use-syslog: no
|
||||
directory: ""
|
||||
pidfile: "unbound.pid"
|
||||
module-config: "respip validator iterator"
|
||||
chroot: ""
|
||||
username: ""
|
||||
do-not-query-localhost: no
|
||||
auth-task-threads: 1
|
||||
log-queries: yes
|
||||
log-replies: yes
|
||||
|
||||
forward-zone:
|
||||
name: "."
|
||||
forward-addr: "127.0.0.1@@TOPORT@"
|
||||
|
||||
rpz:
|
||||
name: "rpz.example.com"
|
||||
for-downstream: yes
|
||||
master: "127.0.0.1@@TOPORT@"
|
||||
rpz-log: yes
|
||||
rpz-log-name: "rpz.example.com"
|
||||
+16
@@ -0,0 +1,16 @@
|
||||
BaseName: auth_load_rpz
|
||||
Version: 1.0
|
||||
Description: Load RPZ zone with auth load thread
|
||||
CreationDate: Tue 6 Oct 10:00:00 CEST 2026
|
||||
Maintainer: dr. W.C.A. Wijngaards
|
||||
Category:
|
||||
Component:
|
||||
CmdDepends:
|
||||
Depends:
|
||||
Help:
|
||||
Pre: auth_load_rpz.pre
|
||||
Post: auth_load_rpz.post
|
||||
Test: auth_load_rpz.test
|
||||
AuxFiles:
|
||||
Passed:
|
||||
Failure:
|
||||
+12
@@ -0,0 +1,12 @@
|
||||
# #-- auth_load_rpz.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
|
||||
cat fwd.log
|
||||
cat unbound.log
|
||||
+39
@@ -0,0 +1,39 @@
|
||||
# #-- auth_load_rpz.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
|
||||
|
||||
PRE="../.."
|
||||
. ../common.sh
|
||||
# if no threads; exit
|
||||
if grep -e "define HAVE_PTHREAD 1" -e "define HAVE_SOLARIS_THREADS 1" -e "define HAVE_WINDOWS_THREADS 1" $PRE/config.h; then
|
||||
echo "have threads"
|
||||
else
|
||||
skip_test "no threads"
|
||||
fi
|
||||
|
||||
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 auth_load_rpz.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'/' < auth_load_rpz.conf > ub.conf
|
||||
# start unbound in the background
|
||||
$PRE/unbound -d -c ub.conf >unbound.log 2>&1 &
|
||||
#valgrind --leak-check=full --show-reachable=yes $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
|
||||
|
||||
+56
@@ -0,0 +1,56 @@
|
||||
# #-- auth_load_rpz.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
|
||||
# The answer is rewritten by RPZ, that is loaded in the auth load thread.
|
||||
echo "> dig www.example.com."
|
||||
dig @127.0.0.1 -p $UNBOUND_PORT www.example.com. | tee outfile
|
||||
if grep SERVFAIL outfile; then
|
||||
echo "> try again"
|
||||
dig @127.0.0.1 -p $UNBOUND_PORT www.example.com. | tee outfile
|
||||
fi
|
||||
if grep SERVFAIL outfile; then
|
||||
echo "> try again"
|
||||
sleep 1
|
||||
dig @127.0.0.1 -p $UNBOUND_PORT www.example.com. | tee outfile
|
||||
fi
|
||||
if grep SERVFAIL outfile; then
|
||||
echo "> try again"
|
||||
sleep 1
|
||||
dig @127.0.0.1 -p $UNBOUND_PORT www.example.com. | tee outfile
|
||||
fi
|
||||
if grep SERVFAIL outfile; then
|
||||
echo "> try again"
|
||||
sleep 1
|
||||
dig @127.0.0.1 -p $UNBOUND_PORT www.example.com. | tee outfile
|
||||
fi
|
||||
if grep SERVFAIL outfile; then
|
||||
echo "> try again"
|
||||
sleep 3
|
||||
dig @127.0.0.1 -p $UNBOUND_PORT www.example.com. | tee outfile
|
||||
fi
|
||||
if grep SERVFAIL outfile; then
|
||||
echo "> try again"
|
||||
sleep 3
|
||||
dig @127.0.0.1 -p $UNBOUND_PORT www.example.com. | tee outfile
|
||||
fi
|
||||
echo "> check answer"
|
||||
if grep "1.2.3.4" outfile; then
|
||||
echo "OK"
|
||||
else
|
||||
echo "Not OK"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
if grep "auth zone rpz.example.com. details" unbound.log; then
|
||||
echo "OK"
|
||||
else
|
||||
echo "not OK"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
exit 0
|
||||
@@ -0,0 +1,22 @@
|
||||
ENTRY_BEGIN
|
||||
MATCH opcode qtype qname
|
||||
ADJUST copy_id
|
||||
REPLY QR AA NOERROR
|
||||
SECTION QUESTION
|
||||
rpz.example.com. IN SOA
|
||||
SECTION ANSWER
|
||||
rpz.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
|
||||
rpz.example.com. IN AXFR
|
||||
SECTION ANSWER
|
||||
rpz.example.com. IN SOA ns.example.com. hostmaster.example.com. 1 3600 900 86400 3600
|
||||
rpz.example.com. IN NS ns.example.net.
|
||||
www.example.com.rpz.example.com. IN A 1.2.3.4
|
||||
rpz.example.com. IN SOA ns.example.com. hostmaster.example.com. 1 3600 900 86400 3600
|
||||
ENTRY_END
|
||||
@@ -0,0 +1,21 @@
|
||||
server:
|
||||
verbosity: 8
|
||||
num-threads: 1
|
||||
interface: 127.0.0.1
|
||||
port: @PORT@
|
||||
use-syslog: no
|
||||
directory: ""
|
||||
pidfile: "unbound.pid"
|
||||
chroot: ""
|
||||
username: ""
|
||||
do-not-query-localhost: no
|
||||
auth-task-threads: 2
|
||||
log-time-ascii: yes
|
||||
log-time-iso: yes
|
||||
|
||||
remote-control:
|
||||
control-enable: yes
|
||||
control-interface: @CONTROL_PATH@/controlpipe.@CONTROL_PID@
|
||||
control-use-cert: no
|
||||
|
||||
include: "auth.zonelist"
|
||||
+16
@@ -0,0 +1,16 @@
|
||||
BaseName: auth_load_tree
|
||||
Version: 1.0
|
||||
Description: Exercise the auth load thread tree in the worker
|
||||
CreationDate: Thu 15 Oct 09:00:00 CEST 2026
|
||||
Maintainer: dr. W.C.A. Wijngaards
|
||||
Category:
|
||||
Component:
|
||||
CmdDepends:
|
||||
Depends:
|
||||
Help:
|
||||
Pre: auth_load_tree.pre
|
||||
Post: auth_load_tree.post
|
||||
Test: auth_load_tree.test
|
||||
AuxFiles:
|
||||
Passed:
|
||||
Failure:
|
||||
@@ -0,0 +1,13 @@
|
||||
# #-- auth_load_tree.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 $UNBOUND_PID
|
||||
kill_pid $FWD_PID
|
||||
rm -f $CONTROL_PATH/controlpipe.$CONTROL_PID
|
||||
cat fwd.log
|
||||
cat unbound.log
|
||||
+108
@@ -0,0 +1,108 @@
|
||||
# #-- auth_load_tree.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
|
||||
|
||||
PRE="../.."
|
||||
. ../common.sh
|
||||
# if no threads; exit
|
||||
if grep -e "define HAVE_PTHREAD 1" -e "define HAVE_SOLARIS_THREADS 1" -e "define HAVE_WINDOWS_THREADS 1" $PRE/config.h; then
|
||||
echo "have threads"
|
||||
else
|
||||
skip_test "no threads"
|
||||
fi
|
||||
|
||||
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
|
||||
|
||||
NUM_AUTH=120
|
||||
echo "NUM_AUTH=$NUM_AUTH" >> .tpkg.var.test
|
||||
echo "" > auth.zonelist
|
||||
|
||||
# start forwarder
|
||||
# create auth_load_tree.testns
|
||||
for((i=1; i<=$NUM_AUTH; i++)); do
|
||||
cat >>auth_load_tree.testns <<EOF
|
||||
|
||||
ENTRY_BEGIN
|
||||
MATCH opcode qtype qname
|
||||
ADJUST copy_id
|
||||
REPLY QR AA NOERROR
|
||||
SECTION QUESTION
|
||||
example$i.com. IN SOA
|
||||
SECTION ANSWER
|
||||
example$i.com. IN SOA ns.example$i.com. hostmaster.example$i.com. 1 3600 900 86400 3600
|
||||
ENTRY_END
|
||||
|
||||
ENTRY_BEGIN
|
||||
MATCH opcode qtype qname
|
||||
ADJUST copy_id
|
||||
REPLY QR AA NOERROR
|
||||
SECTION QUESTION
|
||||
example$i.com. IN AXFR
|
||||
SECTION ANSWER
|
||||
example$i.com. IN SOA ns.example$i.com. hostmaster.example$i.com. 1 3600 900 86400 3600
|
||||
example$i.com. IN NS ns.example.net.
|
||||
EXTRA_PACKET
|
||||
REPLY QR AA NOERROR
|
||||
SECTION QUESTION
|
||||
example$i.com. IN AXFR
|
||||
SECTION ANSWER
|
||||
www.example$i.com. IN A 1.2.3.4
|
||||
h1.example$i.com. IN A 1.2.3.5
|
||||
h2.example$i.com. IN A 1.2.3.5
|
||||
h3.example$i.com. IN A 1.2.3.5
|
||||
h4.example$i.com. IN A 1.2.3.5
|
||||
h5.example$i.com. IN A 1.2.3.5
|
||||
h6.example$i.com. IN A 1.2.3.5
|
||||
h7.example$i.com. IN A 1.2.3.5
|
||||
h8.example$i.com. IN A 1.2.3.5
|
||||
h9.example$i.com. IN A 1.2.3.5
|
||||
h10.example$i.com. IN A 1.2.3.5
|
||||
h11.example$i.com. IN A 1.2.3.5
|
||||
h12.example$i.com. IN A 1.2.3.5
|
||||
h13.example$i.com. IN A 1.2.3.5
|
||||
h14.example$i.com. IN A 1.2.3.5
|
||||
h15.example$i.com. IN A 1.2.3.5
|
||||
h16.example$i.com. IN A 1.2.3.5
|
||||
example$i.com. IN SOA ns.example$i.com. hostmaster.example$i.com. 1 3600 900 86400 3600
|
||||
ENTRY_END
|
||||
EOF
|
||||
|
||||
cat >>auth.zonelist <<EOF
|
||||
auth-zone:
|
||||
name: "example$i.com"
|
||||
for-upstream: yes
|
||||
for-downstream: yes
|
||||
master: "127.0.0.1@${FWD_PORT}@"
|
||||
EOF
|
||||
done
|
||||
get_ldns_testns
|
||||
$LDNS_TESTNS -p $FWD_PORT auth_load_tree.testns >fwd.log 2>&1 &
|
||||
FWD_PID=$!
|
||||
echo "FWD_PID=$FWD_PID" >> .tpkg.var.test
|
||||
|
||||
# make config file
|
||||
CONTROL_PATH=/tmp
|
||||
CONTROL_PID=$$
|
||||
sed -e 's/@PORT\@/'$UNBOUND_PORT'/' \
|
||||
-e 's/@TOPORT\@/'$FWD_PORT'/' \
|
||||
-e 's?@CONTROL_PATH\@?'$CONTROL_PATH'?' \
|
||||
-e 's/@CONTROL_PID@/'$CONTROL_PID'/' \
|
||||
< auth_load_tree.conf > ub.conf
|
||||
# start unbound in the background
|
||||
$PRE/unbound -d -c ub.conf >unbound.log 2>&1 &
|
||||
#valgrind --leak-check=full --show-reachable=yes $PRE/unbound -d -c ub.conf >unbound.log 2>&1 &
|
||||
UNBOUND_PID=$!
|
||||
echo "UNBOUND_PID=$UNBOUND_PID" >> .tpkg.var.test
|
||||
echo "CONTROL_PATH=$CONTROL_PATH" >> .tpkg.var.test
|
||||
echo "CONTROL_PID=$CONTROL_PID" >> .tpkg.var.test
|
||||
|
||||
cat .tpkg.var.test
|
||||
wait_ldns_testns_up fwd.log
|
||||
wait_unbound_up unbound.log
|
||||
|
||||
@@ -0,0 +1,32 @@
|
||||
# #-- auth_load_tree.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="../.."
|
||||
. ../common.sh
|
||||
|
||||
# While the updates are in progress,
|
||||
# perform:
|
||||
# - reload
|
||||
# - stop
|
||||
# This exercises the auth load thread tree in the worker that keeps
|
||||
# track of the connected auth load threads to the worker thread.
|
||||
|
||||
# do the test
|
||||
echo "> unbound-control reload"
|
||||
$PRE/unbound-control -c ub.conf reload
|
||||
if test $? -ne 0; then
|
||||
echo "wrong exit value."
|
||||
exit 1
|
||||
else
|
||||
echo "exit value: OK"
|
||||
fi
|
||||
|
||||
# wait enough to have the reload cause re-fetch to happen during the exit.
|
||||
# for valgrind .4, without .04
|
||||
#sleep .4
|
||||
sleep 0.04
|
||||
|
||||
exit 0
|
||||
+18
@@ -0,0 +1,18 @@
|
||||
diff --git a/services/authload.c b/services/authload.c
|
||||
index 314d1d40b..b0c7336ea 100644
|
||||
--- a/services/authload.c
|
||||
+++ b/services/authload.c
|
||||
@@ -709,6 +709,13 @@ auth_load_thread_process(struct auth_load_thread* thr)
|
||||
if(gettimeofday(&start, NULL) < 0)
|
||||
log_err("gettimeofday: %s", strerror(errno));
|
||||
|
||||
+ if(1) {
|
||||
+ struct timespec dur;
|
||||
+ dur.tv_sec = 1;
|
||||
+ dur.tv_nsec = 500ULL * 1000000ULL;
|
||||
+ nanosleep(&dur, NULL);
|
||||
+ }
|
||||
+
|
||||
/* apply data */
|
||||
if(task->task_type == AUTH_LOAD_TASK_ZONEFILE_WRITE) {
|
||||
if(!auth_load_process_write(thr))
|
||||
@@ -0,0 +1,27 @@
|
||||
server:
|
||||
verbosity: 8
|
||||
# num-threads: 1
|
||||
interface: 127.0.0.1
|
||||
port: @PORT@
|
||||
use-syslog: no
|
||||
directory: ""
|
||||
pidfile: "unbound.pid"
|
||||
module-config: "respip validator iterator"
|
||||
chroot: ""
|
||||
username: ""
|
||||
do-not-query-localhost: no
|
||||
auth-task-threads: 1
|
||||
log-queries: yes
|
||||
log-replies: yes
|
||||
|
||||
forward-zone:
|
||||
name: "."
|
||||
forward-addr: "127.0.0.1@@TOPORT@"
|
||||
|
||||
rpz:
|
||||
name: "rpz.example.com"
|
||||
zonefile: "auth_load_write.zone"
|
||||
for-downstream: yes
|
||||
master: "127.0.0.1@@TOPORT@"
|
||||
rpz-log: yes
|
||||
rpz-log-name: "rpz.example.com"
|
||||
@@ -0,0 +1,16 @@
|
||||
BaseName: auth_load_write
|
||||
Version: 1.0
|
||||
Description: Write zonefile with auth load thread
|
||||
CreationDate: Wed 7 Oct 10:00:00 CEST 2026
|
||||
Maintainer: dr. W.C.A. Wijngaards
|
||||
Category:
|
||||
Component:
|
||||
CmdDepends:
|
||||
Depends:
|
||||
Help:
|
||||
Pre: auth_load_write.pre
|
||||
Post: auth_load_write.post
|
||||
Test: auth_load_write.test
|
||||
AuxFiles:
|
||||
Passed:
|
||||
Failure:
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user