mirror of
https://github.com/NLnetLabs/unbound.git
synced 2026-10-14 04:25:08 +02:00
Compare commits
311
Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
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 | ||
|
|
13b6717f17 | ||
|
|
0d4a6a63dd | ||
|
|
bd71e3b8a6 | ||
|
|
3a6ba0da81 | ||
|
|
3d65973d38 | ||
|
|
565651cd02 | ||
|
|
7914901915 | ||
|
|
eba3d35ad4 | ||
|
|
8c2e0fd6cc | ||
|
|
e619ead2db | ||
|
|
eb86d9bc50 | ||
|
|
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 | ||
|
|
a45da353d3 | ||
|
|
c21e3ee929 | ||
|
|
8a38bed262 | ||
|
|
7cc7a43ff6 | ||
|
|
9bd8df0149 | ||
|
|
8f7411057f | ||
|
|
ca1fe4f82a | ||
|
|
e183c2c506 | ||
|
|
52b18fc6f5 | ||
|
|
e6d00725c2 | ||
|
|
e597711824 | ||
|
|
e1e646c6fc | ||
|
|
fc3b5b4f63 | ||
|
|
1e904a3ce5 | ||
|
|
79e100a7fb | ||
|
|
a65d3d7283 | ||
|
|
3b8766aa43 | ||
|
|
c8b3c89a39 | ||
|
|
a05d460e66 | ||
|
|
5eb362a6c0 | ||
|
|
0735cb28d1 | ||
|
|
737c28e836 | ||
|
|
1bab2dfafa | ||
|
|
22e2c5b6d1 | ||
|
|
914dbfea4e | ||
|
|
cf5e6e89a5 | ||
|
|
4941edf275 | ||
|
|
b08723ef97 | ||
|
|
c163fbc505 | ||
|
|
eed3f1ab38 | ||
|
|
63501f51bb | ||
|
|
1ae2570bda | ||
|
|
9ad825b267 | ||
|
|
3d5e6c0692 | ||
|
|
23e19ca6fc | ||
|
|
9f757aa9f3 | ||
|
|
1df6c170ff | ||
|
|
7a95bedc26 | ||
|
|
ae685bc33d | ||
|
|
91ac449bcd | ||
|
|
c33ad1b1a2 | ||
|
|
84d9682dd0 | ||
|
|
4b1635e194 | ||
|
|
aac261cbb3 | ||
|
|
ae1b3810cc | ||
|
|
96f8755520 | ||
|
|
2ce2ca3691 | ||
|
|
c29ff70f6a | ||
|
|
8a15ffee62 | ||
|
|
8c702de175 | ||
|
|
804cff4c15 | ||
|
|
e180b06298 | ||
|
|
3530c81e29 | ||
|
|
02b16de1ae | ||
|
|
1ad8d4c395 | ||
|
|
364ac737f7 | ||
|
|
f7637a4f18 | ||
|
|
1e1940383a | ||
|
|
f52a9e864b | ||
|
|
13ec8d0f26 | ||
|
|
27f22b8808 | ||
|
|
f54e0791ba | ||
|
|
01dfd2f466 | ||
|
|
f157c691bb | ||
|
|
fea0ff550b | ||
|
|
87d59bfced | ||
|
|
25b2543e5e | ||
|
|
7133e0d32a | ||
|
|
fac7584830 | ||
|
|
87f9258fb4 | ||
|
|
a2fe5356b5 | ||
|
|
ad9b12a863 | ||
|
|
61ca4111a1 | ||
|
|
71a971d70c | ||
|
|
61d6c0e766 | ||
|
|
b4daa2d0fa | ||
|
|
425b701fb9 | ||
|
|
0a5cde80f1 | ||
|
|
58ede90fdb | ||
|
|
ba4f8478e6 | ||
|
|
374a18cc5b | ||
|
|
55ae8da032 | ||
|
|
6bd86df72e | ||
|
|
0efd3605cc | ||
|
|
a2f2f53ef9 | ||
|
|
b5a03093f6 | ||
|
|
8eba898135 | ||
|
|
56f66de89f | ||
|
|
2fbaee2255 | ||
|
|
f35561287a | ||
|
|
672b9659cf | ||
|
|
a122490461 | ||
|
|
7826b4f306 | ||
|
|
380994219f | ||
|
|
153accb8de | ||
|
|
7bb1c62263 | ||
|
|
1578b6e180 | ||
|
|
1978add0cd | ||
|
|
6cbcea3ac7 | ||
|
|
65e23d4b6f | ||
|
|
fbe41cdef9 | ||
|
|
01a95108b3 | ||
|
|
f75d11821f | ||
|
|
6aa5cfc903 | ||
|
|
f6931c794e | ||
|
|
4c5082ad05 | ||
|
|
5fb892a097 | ||
|
|
55e9532d16 | ||
|
|
fff6657cea | ||
|
|
45d1e75caf | ||
|
|
b806f16c8b | ||
|
|
8d3348c71b | ||
|
|
e2cc14681e | ||
|
|
5ae979bb6e | ||
|
|
8f2fbd66fc | ||
|
|
b5909d8d22 | ||
|
|
fa8e94f155 | ||
|
|
cb5683aeae | ||
|
|
c9715724ec | ||
|
|
78d9cfffd8 | ||
|
|
b47b1d048d | ||
|
|
740952fb82 | ||
|
|
5c550f4548 | ||
|
|
3d78cb8d9a | ||
|
|
1ab75c0043 | ||
|
|
bebc8d516b | ||
|
|
a7debe7ff6 | ||
|
|
215e3920ef | ||
|
|
aabf28aef5 | ||
|
|
aa09835c90 | ||
|
|
9b9e13b665 | ||
|
|
f72e11ef5b | ||
|
|
a45e54555d | ||
|
|
4693c00c9f | ||
|
|
8fe23e0297 | ||
|
|
8557788699 | ||
|
|
81a19ebeb3 | ||
|
|
299df5ec77 | ||
|
|
6f9b6db7be | ||
|
|
96f15b9160 | ||
|
|
159384c2a9 | ||
|
|
621fc91453 | ||
|
|
543c49f76c | ||
|
|
d0a760a587 | ||
|
|
f68cca4097 | ||
|
|
3129357874 | ||
|
|
fc09352df6 | ||
|
|
06da5d45a3 | ||
|
|
69524cadad | ||
|
|
98e95d80e6 | ||
|
|
2f8aa8a43a | ||
|
|
56e60e37ae | ||
|
|
8f5348ab47 | ||
|
|
c5d693b21c | ||
|
|
27e3ac55b9 | ||
|
|
7879218773 | ||
|
|
1354624ba4 | ||
|
|
153f8d5353 | ||
|
|
a1cecf7462 | ||
|
|
e2dac8a00a | ||
|
|
ecd41bef27 | ||
|
|
fd2131687a | ||
|
|
316b9ab4fc | ||
|
|
d45daaf313 | ||
|
|
db1c6d6557 | ||
|
|
e7a713a525 | ||
|
|
39e67508c9 | ||
|
|
3eab974ca2 | ||
|
|
b1d1dcb3b6 | ||
|
|
10cb62aca2 | ||
|
|
6da73aba38 | ||
|
|
1b1b9626ee | ||
|
|
8bc074043a | ||
|
|
04a6322aa4 | ||
|
|
5748f518d1 | ||
|
|
d05eff4d54 | ||
|
|
4544eaa4cc | ||
|
|
5d0770d0ad | ||
|
|
7f4beb846e | ||
|
|
8e8c04e1b9 | ||
|
|
bf0da2ed21 | ||
|
|
670ece06df | ||
|
|
9e41903be8 | ||
|
|
57f92cc97e | ||
|
|
c0741ccc68 | ||
|
|
fb2745024a | ||
|
|
0c15ddd133 | ||
|
|
b53504049c | ||
|
|
a5324e58eb | ||
|
|
963cd68535 | ||
|
|
047df73887 | ||
|
|
d2e1ea7d19 | ||
|
|
fbbe95ba5b | ||
|
|
758c649611 | ||
|
|
a23f95f620 | ||
|
|
5363570df0 | ||
|
|
368857a45b | ||
|
|
40b16d0565 | ||
|
|
08e901a1ac | ||
|
|
bc703c9129 | ||
|
|
9ce52de6c1 | ||
|
|
b3aa262477 | ||
|
|
25e112c674 | ||
|
|
0d2282d551 | ||
|
|
b5f21f4165 | ||
|
|
d357935f66 | ||
|
|
9d2e0f1c02 | ||
|
|
b46ff5c18e | ||
|
|
f597105800 | ||
|
|
3692517a41 | ||
|
|
a58bd6cb1e | ||
|
|
4bad944ae4 | ||
|
|
594182f109 | ||
|
|
53c261cb33 | ||
|
|
8703d9a5be | ||
|
|
aa9f1e68ff | ||
|
|
84a4f556b1 | ||
|
|
5b166dbf0a | ||
|
|
9e2233b821 | ||
|
|
13716dc8be | ||
|
|
8ada1bd88d | ||
|
|
9c80bb9fb0 | ||
|
|
33e2863862 | ||
|
|
027e23a11d | ||
|
|
62e8db1c6a | ||
|
|
581b2f31bc |
@@ -173,7 +173,7 @@ jobs:
|
||||
cross_platform_config: "--enable-debug --disable-flto --with-libevent --disable-static"
|
||||
|
||||
steps:
|
||||
- uses: actions/checkout@v6
|
||||
- uses: actions/checkout@v7
|
||||
with:
|
||||
submodules: false
|
||||
persist-credentials: false
|
||||
|
||||
@@ -12,7 +12,7 @@ jobs:
|
||||
runs-on: ubuntu-latest
|
||||
|
||||
steps:
|
||||
- uses: actions/checkout@v6
|
||||
- uses: actions/checkout@v7
|
||||
with:
|
||||
persist-credentials: false
|
||||
- name: configure
|
||||
|
||||
-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
|
||||
+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 \
|
||||
|
||||
@@ -10,7 +10,7 @@ Unbound is a validating, recursive, caching DNS resolver. It is designed to be
|
||||
fast and lean and incorporates modern features based on open standards. If you
|
||||
have any feedback, we would love to hear from you. Don’t hesitate to
|
||||
[create an issue on Github](https://github.com/NLnetLabs/unbound/issues/new)
|
||||
or post a message on the [Unbound mailing list](https://lists.nlnetlabs.nl/mailman/listinfo/unbound-users).
|
||||
or post a message on our [community forum](https://community.nlnetlabs.nl/).
|
||||
You can learn more about Unbound by reading our
|
||||
[documentation](https://unbound.docs.nlnetlabs.nl/).
|
||||
|
||||
|
||||
+17
-2
@@ -87,7 +87,7 @@
|
||||
# modified version of the Autoconf Macro, you may extend this special
|
||||
# exception to the GPL to apply to your modified version as well.
|
||||
|
||||
#serial 31
|
||||
#serial 32
|
||||
|
||||
AU_ALIAS([ACX_PTHREAD], [AX_PTHREAD])
|
||||
AC_DEFUN([AX_PTHREAD], [
|
||||
@@ -249,7 +249,22 @@ AS_IF([test "x$ax_pthread_clang" = "xyes"],
|
||||
# correctly enabled
|
||||
|
||||
case $host_os in
|
||||
darwin* | hpux* | linux* | osf* | solaris*)
|
||||
solaris*)
|
||||
# Solaris 11.4 introduced XPG7 support and did away with the need for
|
||||
# _REENTRANT.
|
||||
|
||||
AC_EGREP_CPP([AX_PTHREAD_SOLARIS__REENTRANT],
|
||||
[
|
||||
# undef _XOPEN_SOURCE
|
||||
# include <sys/feature_tests.h>
|
||||
# if _XOPEN_VERSION < 700
|
||||
AX_PTHREAD_SOLARIS__REENTRANT
|
||||
# endif
|
||||
],
|
||||
[ax_pthread_check_macro="_REENTRANT"],
|
||||
[ax_pthread_check_macro="--"])
|
||||
;;
|
||||
darwin* | hpux* | linux* | osf*)
|
||||
ax_pthread_check_macro="_REENTRANT"
|
||||
;;
|
||||
|
||||
|
||||
@@ -401,6 +401,12 @@ prep_data(struct module_qstate* qstate, struct sldns_buffer* buf)
|
||||
FLAGS_GET_RCODE(qstate->return_msg->rep->flags) !=
|
||||
LDNS_RCODE_YXDOMAIN)
|
||||
return 0;
|
||||
/* Do not persist data the validator has not yet seen, or has rejected.
|
||||
* Otherwise an expired blob could maybe reach clients via
|
||||
* serve-expired. */
|
||||
if(qstate->env->need_to_validate &&
|
||||
qstate->return_msg->rep->security == sec_status_bogus)
|
||||
return 0;
|
||||
/* We don't store the reply if its TTL is 0. This is probably coming
|
||||
* from upstream and it is not meant to be stored. */
|
||||
if(qstate->return_msg->rep->ttl == 0)
|
||||
@@ -863,6 +869,11 @@ cachedb_handle_query(struct module_qstate* qstate,
|
||||
return;
|
||||
}
|
||||
/* No 0TTL answers escaping from external cache. */
|
||||
if(qstate->return_msg->rep->ttl == 0) {
|
||||
qstate->return_msg = NULL;
|
||||
qstate->ext_state[id] = module_wait_module;
|
||||
return;
|
||||
}
|
||||
log_assert(qstate->return_msg->rep->ttl > 0);
|
||||
qstate->is_cachedb_answer = 1;
|
||||
/* we are done with the query */
|
||||
|
||||
+9
-382
@@ -20,398 +20,25 @@
|
||||
* http://man.openbsd.org/getentropy.2
|
||||
*/
|
||||
|
||||
#include <TargetConditionals.h>
|
||||
#include <sys/types.h>
|
||||
#include <sys/param.h>
|
||||
#include <sys/ioctl.h>
|
||||
#include <sys/resource.h>
|
||||
#include <sys/syscall.h>
|
||||
#include <sys/sysctl.h>
|
||||
#include <sys/statvfs.h>
|
||||
#include <sys/socket.h>
|
||||
#include <sys/mount.h>
|
||||
#include <sys/mman.h>
|
||||
#include <sys/stat.h>
|
||||
#include <sys/time.h>
|
||||
#include <stdlib.h>
|
||||
#include <stdint.h>
|
||||
#include <stdio.h>
|
||||
#include <termios.h>
|
||||
#include <fcntl.h>
|
||||
#include <signal.h>
|
||||
#include <string.h>
|
||||
/* Modified to use SecRandomCopyBytes. It is from macOS 10.7 (2011) and
|
||||
* iOS 2.0 (2008), and is the primary API for cryptographic random numbers. */
|
||||
#include <errno.h>
|
||||
#include <unistd.h>
|
||||
#include <time.h>
|
||||
#include <mach/mach_time.h>
|
||||
#include <mach/mach_host.h>
|
||||
#include <mach/host_info.h>
|
||||
#if TARGET_OS_OSX
|
||||
#include <sys/socketvar.h>
|
||||
#include <sys/vmmeter.h>
|
||||
#endif
|
||||
#include <netinet/in.h>
|
||||
#include <netinet/tcp.h>
|
||||
#if TARGET_OS_OSX
|
||||
#include <netinet/udp.h>
|
||||
#include <netinet/ip_var.h>
|
||||
#include <netinet/tcp_var.h>
|
||||
#include <netinet/udp_var.h>
|
||||
#endif
|
||||
#include <CommonCrypto/CommonDigest.h>
|
||||
#define SHA512_Update(a, b, c) (CC_SHA512_Update((a), (b), (c)))
|
||||
#define SHA512_Init(xxx) (CC_SHA512_Init((xxx)))
|
||||
#define SHA512_Final(xxx, yyy) (CC_SHA512_Final((xxx), (yyy)))
|
||||
#define SHA512_CTX CC_SHA512_CTX
|
||||
#define SHA512_DIGEST_LENGTH CC_SHA512_DIGEST_LENGTH
|
||||
|
||||
#define REPEAT 5
|
||||
#define min(a, b) (((a) < (b)) ? (a) : (b))
|
||||
|
||||
#define HX(a, b) \
|
||||
do { \
|
||||
if ((a)) \
|
||||
HD(errno); \
|
||||
else \
|
||||
HD(b); \
|
||||
} while (0)
|
||||
|
||||
#define HR(x, l) (SHA512_Update(&ctx, (char *)(x), (l)))
|
||||
#define HD(x) (SHA512_Update(&ctx, (char *)&(x), sizeof (x)))
|
||||
#define HF(x) (SHA512_Update(&ctx, (char *)&(x), sizeof (void*)))
|
||||
#include <Security/SecRandom.h>
|
||||
|
||||
int getentropy(void *buf, size_t len);
|
||||
|
||||
static int getentropy_urandom(void *buf, size_t len);
|
||||
static int getentropy_fallback(void *buf, size_t len);
|
||||
|
||||
int
|
||||
getentropy(void *buf, size_t len)
|
||||
{
|
||||
int ret = -1;
|
||||
|
||||
if (len > 256) {
|
||||
errno = EIO;
|
||||
return (-1);
|
||||
goto error;
|
||||
}
|
||||
|
||||
/*
|
||||
* Try to get entropy with /dev/urandom
|
||||
*
|
||||
* This can fail if the process is inside a chroot or if file
|
||||
* descriptors are exhausted.
|
||||
*/
|
||||
ret = getentropy_urandom(buf, len);
|
||||
if (ret != -1)
|
||||
return (ret);
|
||||
|
||||
/*
|
||||
* Entropy collection via /dev/urandom and sysctl have failed.
|
||||
*
|
||||
* No other API exists for collecting entropy, and we have
|
||||
* no failsafe way to get it on OSX that is not sensitive
|
||||
* to resource exhaustion.
|
||||
*
|
||||
* We have very few options:
|
||||
* - Even syslog_r is unsafe to call at this low level, so
|
||||
* there is no way to alert the user or program.
|
||||
* - Cannot call abort() because some systems have unsafe
|
||||
* corefiles.
|
||||
* - Could raise(SIGKILL) resulting in silent program termination.
|
||||
* - Return EIO, to hint that arc4random's stir function
|
||||
* should raise(SIGKILL)
|
||||
* - Do the best under the circumstances....
|
||||
*
|
||||
* This code path exists to bring light to the issue that OSX
|
||||
* does not provide a failsafe API for entropy collection.
|
||||
*
|
||||
* We hope this demonstrates that OSX should consider
|
||||
* providing a new failsafe API which works in a chroot or
|
||||
* when file descriptors are exhausted.
|
||||
*/
|
||||
#undef FAIL_INSTEAD_OF_TRYING_FALLBACK
|
||||
#ifdef FAIL_INSTEAD_OF_TRYING_FALLBACK
|
||||
raise(SIGKILL);
|
||||
#endif
|
||||
ret = getentropy_fallback(buf, len);
|
||||
if (ret != -1)
|
||||
return (ret);
|
||||
if (SecRandomCopyBytes(kSecRandomDefault, len, buf) == errSecSuccess) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
error:
|
||||
errno = EIO;
|
||||
return (ret);
|
||||
}
|
||||
|
||||
static int
|
||||
getentropy_urandom(void *buf, size_t len)
|
||||
{
|
||||
struct stat st;
|
||||
size_t i;
|
||||
int fd, flags;
|
||||
int save_errno = errno;
|
||||
|
||||
start:
|
||||
|
||||
flags = O_RDONLY;
|
||||
#ifdef O_NOFOLLOW
|
||||
flags |= O_NOFOLLOW;
|
||||
#endif
|
||||
#ifdef O_CLOEXEC
|
||||
flags |= O_CLOEXEC;
|
||||
#endif
|
||||
fd = open("/dev/urandom", flags, 0);
|
||||
if (fd == -1) {
|
||||
if (errno == EINTR)
|
||||
goto start;
|
||||
goto nodevrandom;
|
||||
}
|
||||
#ifndef O_CLOEXEC
|
||||
fcntl(fd, F_SETFD, fcntl(fd, F_GETFD) | FD_CLOEXEC);
|
||||
#endif
|
||||
|
||||
/* Lightly verify that the device node looks sane */
|
||||
if (fstat(fd, &st) == -1 || !S_ISCHR(st.st_mode)) {
|
||||
close(fd);
|
||||
goto nodevrandom;
|
||||
}
|
||||
for (i = 0; i < len; ) {
|
||||
size_t wanted = len - i;
|
||||
ssize_t ret = read(fd, (char *)buf + i, wanted);
|
||||
|
||||
if (ret == -1) {
|
||||
if (errno == EAGAIN || errno == EINTR)
|
||||
continue;
|
||||
close(fd);
|
||||
goto nodevrandom;
|
||||
}
|
||||
i += ret;
|
||||
}
|
||||
close(fd);
|
||||
errno = save_errno;
|
||||
return (0); /* satisfied */
|
||||
nodevrandom:
|
||||
errno = EIO;
|
||||
return (-1);
|
||||
}
|
||||
|
||||
#if TARGET_OS_OSX
|
||||
static int tcpmib[] = { CTL_NET, AF_INET, IPPROTO_TCP, TCPCTL_STATS };
|
||||
static int udpmib[] = { CTL_NET, AF_INET, IPPROTO_UDP, UDPCTL_STATS };
|
||||
static int ipmib[] = { CTL_NET, AF_INET, IPPROTO_IP, IPCTL_STATS };
|
||||
#endif
|
||||
static int kmib[] = { CTL_KERN, KERN_USRSTACK };
|
||||
static int hwmib[] = { CTL_HW, HW_USERMEM };
|
||||
|
||||
static int
|
||||
getentropy_fallback(void *buf, size_t len)
|
||||
{
|
||||
uint8_t results[SHA512_DIGEST_LENGTH];
|
||||
int save_errno = errno, e, pgs = getpagesize(), faster = 0, repeat;
|
||||
static int cnt;
|
||||
struct timespec ts;
|
||||
struct timeval tv;
|
||||
struct rusage ru;
|
||||
sigset_t sigset;
|
||||
struct stat st;
|
||||
SHA512_CTX ctx;
|
||||
static pid_t lastpid;
|
||||
pid_t pid;
|
||||
size_t i, ii, m;
|
||||
char *p;
|
||||
#if TARGET_OS_OSX
|
||||
struct tcpstat tcpstat;
|
||||
struct udpstat udpstat;
|
||||
struct ipstat ipstat;
|
||||
#endif
|
||||
u_int64_t mach_time;
|
||||
unsigned int idata;
|
||||
void *addr;
|
||||
|
||||
pid = getpid();
|
||||
if (lastpid == pid) {
|
||||
faster = 1;
|
||||
repeat = 2;
|
||||
} else {
|
||||
faster = 0;
|
||||
lastpid = pid;
|
||||
repeat = REPEAT;
|
||||
}
|
||||
for (i = 0; i < len; ) {
|
||||
int j;
|
||||
SHA512_Init(&ctx);
|
||||
for (j = 0; j < repeat; j++) {
|
||||
HX((e = gettimeofday(&tv, NULL)) == -1, tv);
|
||||
if (e != -1) {
|
||||
cnt += (int)tv.tv_sec;
|
||||
cnt += (int)tv.tv_usec;
|
||||
}
|
||||
|
||||
mach_time = mach_absolute_time();
|
||||
HD(mach_time);
|
||||
|
||||
ii = sizeof(addr);
|
||||
HX(sysctl(kmib, sizeof(kmib) / sizeof(kmib[0]),
|
||||
&addr, &ii, NULL, 0) == -1, addr);
|
||||
|
||||
ii = sizeof(idata);
|
||||
HX(sysctl(hwmib, sizeof(hwmib) / sizeof(hwmib[0]),
|
||||
&idata, &ii, NULL, 0) == -1, idata);
|
||||
|
||||
#if TARGET_OS_OSX
|
||||
ii = sizeof(tcpstat);
|
||||
HX(sysctl(tcpmib, sizeof(tcpmib) / sizeof(tcpmib[0]),
|
||||
&tcpstat, &ii, NULL, 0) == -1, tcpstat);
|
||||
|
||||
ii = sizeof(udpstat);
|
||||
HX(sysctl(udpmib, sizeof(udpmib) / sizeof(udpmib[0]),
|
||||
&udpstat, &ii, NULL, 0) == -1, udpstat);
|
||||
|
||||
ii = sizeof(ipstat);
|
||||
HX(sysctl(ipmib, sizeof(ipmib) / sizeof(ipmib[0]),
|
||||
&ipstat, &ii, NULL, 0) == -1, ipstat);
|
||||
#endif
|
||||
|
||||
HX((pid = getpid()) == -1, pid);
|
||||
HX((pid = getsid(pid)) == -1, pid);
|
||||
HX((pid = getppid()) == -1, pid);
|
||||
HX((pid = getpgid(0)) == -1, pid);
|
||||
HX((e = getpriority(0, 0)) == -1, e);
|
||||
|
||||
if (!faster) {
|
||||
ts.tv_sec = 0;
|
||||
ts.tv_nsec = 1;
|
||||
(void) nanosleep(&ts, NULL);
|
||||
}
|
||||
|
||||
HX(sigpending(&sigset) == -1, sigset);
|
||||
HX(sigprocmask(SIG_BLOCK, NULL, &sigset) == -1,
|
||||
sigset);
|
||||
|
||||
HF(getentropy); /* an addr in this library */
|
||||
HF(printf); /* an addr in libc */
|
||||
p = (char *)&p;
|
||||
HD(p); /* an addr on stack */
|
||||
p = (char *)&errno;
|
||||
HD(p); /* the addr of errno */
|
||||
|
||||
if (i == 0) {
|
||||
struct sockaddr_storage ss;
|
||||
struct statvfs stvfs;
|
||||
struct termios tios;
|
||||
struct statfs stfs;
|
||||
socklen_t ssl;
|
||||
off_t off;
|
||||
|
||||
/*
|
||||
* Prime-sized mappings encourage fragmentation;
|
||||
* thus exposing some address entropy.
|
||||
*/
|
||||
struct mm {
|
||||
size_t npg;
|
||||
void *p;
|
||||
} mm[] = {
|
||||
{ 17, MAP_FAILED }, { 3, MAP_FAILED },
|
||||
{ 11, MAP_FAILED }, { 2, MAP_FAILED },
|
||||
{ 5, MAP_FAILED }, { 3, MAP_FAILED },
|
||||
{ 7, MAP_FAILED }, { 1, MAP_FAILED },
|
||||
{ 57, MAP_FAILED }, { 3, MAP_FAILED },
|
||||
{ 131, MAP_FAILED }, { 1, MAP_FAILED },
|
||||
};
|
||||
|
||||
for (m = 0; m < sizeof mm/sizeof(mm[0]); m++) {
|
||||
HX(mm[m].p = mmap(NULL,
|
||||
mm[m].npg * pgs,
|
||||
PROT_READ|PROT_WRITE,
|
||||
MAP_PRIVATE|MAP_ANON, -1,
|
||||
(off_t)0), mm[m].p);
|
||||
if (mm[m].p != MAP_FAILED) {
|
||||
size_t mo;
|
||||
|
||||
/* Touch some memory... */
|
||||
p = mm[m].p;
|
||||
mo = cnt %
|
||||
(mm[m].npg * pgs - 1);
|
||||
p[mo] = 1;
|
||||
cnt += (int)((long)(mm[m].p)
|
||||
/ pgs);
|
||||
}
|
||||
|
||||
/* Check cnts and times... */
|
||||
mach_time = mach_absolute_time();
|
||||
HD(mach_time);
|
||||
cnt += (int)mach_time;
|
||||
|
||||
HX((e = getrusage(RUSAGE_SELF,
|
||||
&ru)) == -1, ru);
|
||||
if (e != -1) {
|
||||
cnt += (int)ru.ru_utime.tv_sec;
|
||||
cnt += (int)ru.ru_utime.tv_usec;
|
||||
}
|
||||
}
|
||||
|
||||
for (m = 0; m < sizeof mm/sizeof(mm[0]); m++) {
|
||||
if (mm[m].p != MAP_FAILED)
|
||||
munmap(mm[m].p, mm[m].npg * pgs);
|
||||
mm[m].p = MAP_FAILED;
|
||||
}
|
||||
|
||||
HX(stat(".", &st) == -1, st);
|
||||
HX(statvfs(".", &stvfs) == -1, stvfs);
|
||||
HX(statfs(".", &stfs) == -1, stfs);
|
||||
|
||||
HX(stat("/", &st) == -1, st);
|
||||
HX(statvfs("/", &stvfs) == -1, stvfs);
|
||||
HX(statfs("/", &stfs) == -1, stfs);
|
||||
|
||||
HX((e = fstat(0, &st)) == -1, st);
|
||||
if (e == -1) {
|
||||
if (S_ISREG(st.st_mode) ||
|
||||
S_ISFIFO(st.st_mode) ||
|
||||
S_ISSOCK(st.st_mode)) {
|
||||
HX(fstatvfs(0, &stvfs) == -1,
|
||||
stvfs);
|
||||
HX(fstatfs(0, &stfs) == -1,
|
||||
stfs);
|
||||
HX((off = lseek(0, (off_t)0,
|
||||
SEEK_CUR)) < 0, off);
|
||||
}
|
||||
if (S_ISCHR(st.st_mode)) {
|
||||
HX(tcgetattr(0, &tios) == -1,
|
||||
tios);
|
||||
} else if (S_ISSOCK(st.st_mode)) {
|
||||
memset(&ss, 0, sizeof ss);
|
||||
ssl = sizeof(ss);
|
||||
HX(getpeername(0,
|
||||
(void *)&ss, &ssl) == -1,
|
||||
ss);
|
||||
}
|
||||
}
|
||||
|
||||
HX((e = getrusage(RUSAGE_CHILDREN,
|
||||
&ru)) == -1, ru);
|
||||
if (e != -1) {
|
||||
cnt += (int)ru.ru_utime.tv_sec;
|
||||
cnt += (int)ru.ru_utime.tv_usec;
|
||||
}
|
||||
} else {
|
||||
/* Subsequent hashes absorb previous result */
|
||||
HD(results);
|
||||
}
|
||||
|
||||
HX((e = gettimeofday(&tv, NULL)) == -1, tv);
|
||||
if (e != -1) {
|
||||
cnt += (int)tv.tv_sec;
|
||||
cnt += (int)tv.tv_usec;
|
||||
}
|
||||
|
||||
HD(cnt);
|
||||
}
|
||||
|
||||
SHA512_Final(results, &ctx);
|
||||
memcpy((char *)buf + i, results, min(sizeof(results), len - i));
|
||||
i += min(sizeof(results), len - i);
|
||||
}
|
||||
explicit_bzero(&ctx, sizeof ctx);
|
||||
explicit_bzero(results, sizeof results);
|
||||
errno = save_errno;
|
||||
return (0); /* satisfied */
|
||||
return -1;
|
||||
}
|
||||
|
||||
+3
-10
@@ -59,10 +59,7 @@ static int inet_pton6 (const char *src, uint8_t *dst);
|
||||
* Paul Vixie, 1996.
|
||||
*/
|
||||
int
|
||||
inet_pton(af, src, dst)
|
||||
int af;
|
||||
const char *src;
|
||||
void *dst;
|
||||
inet_pton(int af, const char *src, void *dst)
|
||||
{
|
||||
switch (af) {
|
||||
case AF_INET:
|
||||
@@ -91,9 +88,7 @@ inet_pton(af, src, dst)
|
||||
* Paul Vixie, 1996.
|
||||
*/
|
||||
static int
|
||||
inet_pton4(src, dst)
|
||||
const char *src;
|
||||
uint8_t *dst;
|
||||
inet_pton4(const char *src, uint8_t *dst)
|
||||
{
|
||||
static const char digits[] = "0123456789";
|
||||
int saw_digit, octets, ch;
|
||||
@@ -145,9 +140,7 @@ inet_pton4(src, dst)
|
||||
* Paul Vixie, 1996.
|
||||
*/
|
||||
static int
|
||||
inet_pton6(src, dst)
|
||||
const char *src;
|
||||
uint8_t *dst;
|
||||
inet_pton6(const char *src, uint8_t *dst)
|
||||
{
|
||||
static const char xdigits_l[] = "0123456789abcdef",
|
||||
xdigits_u[] = "0123456789ABCDEF";
|
||||
|
||||
+32
@@ -31,6 +31,9 @@
|
||||
/* Whether daemon is deprecated */
|
||||
#undef DEPRECATED_DAEMON
|
||||
|
||||
/* Whether X509_NAME_get_text_by_NID is deprecated */
|
||||
#undef DEPRECATED_X509_NAME_GET_TEXT_BY_NID
|
||||
|
||||
/* Deprecate RSA 1024 bit length, makes that an unsupported key */
|
||||
#undef DEPRECATE_RSA_1024
|
||||
|
||||
@@ -60,6 +63,9 @@
|
||||
/* Define to 1 if you have the <arpa/inet.h> header file. */
|
||||
#undef HAVE_ARPA_INET_H
|
||||
|
||||
/* Define to 1 if you have the `ASN1_STRING_get0_data' function. */
|
||||
#undef HAVE_ASN1_STRING_GET0_DATA
|
||||
|
||||
/* Whether the C compiler accepts the "fallthrough" attribute */
|
||||
#undef HAVE_ATTR_FALLTHROUGH
|
||||
|
||||
@@ -140,6 +146,10 @@
|
||||
to 0 if you don't. */
|
||||
#undef HAVE_DECL_NGTCP2_CRYPTO_ENCRYPT_CB
|
||||
|
||||
/* Define to 1 if you have the declaration of `ngtcp2_crypto_ossl_ctx_new',
|
||||
and to 0 if you don't. */
|
||||
#undef HAVE_DECL_NGTCP2_CRYPTO_OSSL_CTX_NEW
|
||||
|
||||
/* Define to 1 if you have the declaration of `NID_ED25519', and to 0 if you
|
||||
don't. */
|
||||
#undef HAVE_DECL_NID_ED25519
|
||||
@@ -289,6 +299,12 @@
|
||||
/* Define to 1 if you have the `FIPS_mode' function. */
|
||||
#undef HAVE_FIPS_MODE
|
||||
|
||||
/* Define to 1 if you have the `fnmatch' function. */
|
||||
#undef HAVE_FNMATCH
|
||||
|
||||
/* Define to 1 if you have the <fnmatch.h> header file. */
|
||||
#undef HAVE_FNMATCH_H
|
||||
|
||||
/* Define to 1 if you have the `fork' function. */
|
||||
#undef HAVE_FORK
|
||||
|
||||
@@ -513,6 +529,9 @@
|
||||
/* Define to 1 if you have the <openssl/bn.h> header file. */
|
||||
#undef HAVE_OPENSSL_BN_H
|
||||
|
||||
/* Define to 1 if you have the `OPENSSL_cleanup' function. */
|
||||
#undef HAVE_OPENSSL_CLEANUP
|
||||
|
||||
/* Define to 1 if you have the `OPENSSL_config' function. */
|
||||
#undef HAVE_OPENSSL_CONFIG
|
||||
|
||||
@@ -685,9 +704,16 @@
|
||||
/* Define to 1 if you have the `SSL_is_quic' function. */
|
||||
#undef HAVE_SSL_IS_QUIC
|
||||
|
||||
/* Define to 1 if you have the `SSL_set1_dnsname' function. */
|
||||
#undef HAVE_SSL_SET1_DNSNAME
|
||||
|
||||
/* Define to 1 if you have the `SSL_set1_host' function. */
|
||||
#undef HAVE_SSL_SET1_HOST
|
||||
|
||||
/* Define to 1 if you have the `SSL_set_quic_tls_early_data_enabled' function.
|
||||
*/
|
||||
#undef HAVE_SSL_SET_QUIC_TLS_EARLY_DATA_ENABLED
|
||||
|
||||
/* Define to 1 if you have the <stdarg.h> header file. */
|
||||
#undef HAVE_STDARG_H
|
||||
|
||||
@@ -852,6 +878,12 @@
|
||||
/* Define to 1 if you have the <ws2tcpip.h> header file. */
|
||||
#undef HAVE_WS2TCPIP_H
|
||||
|
||||
/* Define to 1 if you have the `X509_get_key_usage' function. */
|
||||
#undef HAVE_X509_GET_KEY_USAGE
|
||||
|
||||
/* Define to 1 if you have the `X509_NAME_get_text_by_NID' function. */
|
||||
#undef HAVE_X509_NAME_GET_TEXT_BY_NID
|
||||
|
||||
/* Define to 1 if you have the `X509_VERIFY_PARAM_set1_host' function. */
|
||||
#undef HAVE_X509_VERIFY_PARAM_SET1_HOST
|
||||
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
#! /bin/sh
|
||||
# Guess values for system-dependent variables and create Makefiles.
|
||||
# Generated by GNU Autoconf 2.71 for unbound 1.25.1.
|
||||
# Generated by GNU Autoconf 2.71 for unbound 1.26.2.
|
||||
#
|
||||
# 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.25.1'
|
||||
PACKAGE_STRING='unbound 1.25.1'
|
||||
PACKAGE_VERSION='1.26.2'
|
||||
PACKAGE_STRING='unbound 1.26.2'
|
||||
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.25.1 to adapt to many kinds of systems.
|
||||
\`configure' configures unbound 1.26.2 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.25.1:";;
|
||||
short | recursive ) echo "Configuration of unbound 1.26.2:";;
|
||||
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.25.1
|
||||
unbound configure 1.26.2
|
||||
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.25.1, which was
|
||||
It was created by unbound $as_me 1.26.2, which was
|
||||
generated by GNU Autoconf 2.71. Invocation command line was
|
||||
|
||||
$ $0$ac_configure_args_raw
|
||||
@@ -3251,13 +3251,13 @@ ac_compiler_gnu=$ac_cv_c_compiler_gnu
|
||||
|
||||
UNBOUND_VERSION_MAJOR=1
|
||||
|
||||
UNBOUND_VERSION_MINOR=25
|
||||
UNBOUND_VERSION_MINOR=26
|
||||
|
||||
UNBOUND_VERSION_MICRO=1
|
||||
UNBOUND_VERSION_MICRO=2
|
||||
|
||||
|
||||
LIBUNBOUND_CURRENT=9
|
||||
LIBUNBOUND_REVISION=37
|
||||
LIBUNBOUND_REVISION=41
|
||||
LIBUNBOUND_AGE=1
|
||||
# 1.0.0 had 0:12:0
|
||||
# 1.0.1 had 0:13:0
|
||||
@@ -3362,6 +3362,10 @@ LIBUNBOUND_AGE=1
|
||||
# 1.24.2 had 9:35:1
|
||||
# 1.25.0 had 9:36:1
|
||||
# 1.25.1 had 9:37:1
|
||||
# 1.25.2 had 9:38:1
|
||||
# 1.26.0 had 9:39:1
|
||||
# 1.26.1 had 9:40:1
|
||||
# 1.26.2 had 9:41:1
|
||||
|
||||
# Current -- the number of the binary API that we're implementing
|
||||
# Revision -- which iteration of the implementation of the binary
|
||||
@@ -16004,6 +16008,13 @@ if test "x$ac_cv_header_glob_h" = xyes
|
||||
then :
|
||||
printf "%s\n" "#define HAVE_GLOB_H 1" >>confdefs.h
|
||||
|
||||
fi
|
||||
ac_fn_c_check_header_compile "$LINENO" "fnmatch.h" "ac_cv_header_fnmatch_h" "$ac_includes_default
|
||||
"
|
||||
if test "x$ac_cv_header_fnmatch_h" = xyes
|
||||
then :
|
||||
printf "%s\n" "#define HAVE_FNMATCH_H 1" >>confdefs.h
|
||||
|
||||
fi
|
||||
ac_fn_c_check_header_compile "$LINENO" "grp.h" "ac_cv_header_grp_h" "$ac_includes_default
|
||||
"
|
||||
@@ -18406,7 +18417,31 @@ fi
|
||||
# correctly enabled
|
||||
|
||||
case $host_os in
|
||||
darwin* | hpux* | linux* | osf* | solaris*)
|
||||
solaris*)
|
||||
# Solaris 11.4 introduced XPG7 support and did away with the need for
|
||||
# _REENTRANT.
|
||||
|
||||
cat confdefs.h - <<_ACEOF >conftest.$ac_ext
|
||||
/* end confdefs.h. */
|
||||
|
||||
# undef _XOPEN_SOURCE
|
||||
# include <sys/feature_tests.h>
|
||||
# if _XOPEN_VERSION < 700
|
||||
AX_PTHREAD_SOLARIS__REENTRANT
|
||||
# endif
|
||||
|
||||
_ACEOF
|
||||
if (eval "$ac_cpp conftest.$ac_ext") 2>&5 |
|
||||
$EGREP "AX_PTHREAD_SOLARIS__REENTRANT" >/dev/null 2>&1
|
||||
then :
|
||||
ax_pthread_check_macro="_REENTRANT"
|
||||
else $as_nop
|
||||
ax_pthread_check_macro="--"
|
||||
fi
|
||||
rm -rf conftest*
|
||||
|
||||
;;
|
||||
darwin* | hpux* | linux* | osf*)
|
||||
ax_pthread_check_macro="_REENTRANT"
|
||||
;;
|
||||
|
||||
@@ -21060,6 +21095,12 @@ then :
|
||||
printf "%s\n" "#define HAVE_BIO_SET_CALLBACK_EX 1" >>confdefs.h
|
||||
|
||||
fi
|
||||
ac_fn_c_check_func "$LINENO" "OPENSSL_cleanup" "ac_cv_func_OPENSSL_cleanup"
|
||||
if test "x$ac_cv_func_OPENSSL_cleanup" = xyes
|
||||
then :
|
||||
printf "%s\n" "#define HAVE_OPENSSL_CLEANUP 1" >>confdefs.h
|
||||
|
||||
fi
|
||||
|
||||
|
||||
# these check_funcs need -lssl
|
||||
@@ -21088,6 +21129,24 @@ if test "x$ac_cv_func_SSL_get0_peername" = xyes
|
||||
then :
|
||||
printf "%s\n" "#define HAVE_SSL_GET0_PEERNAME 1" >>confdefs.h
|
||||
|
||||
fi
|
||||
ac_fn_c_check_func "$LINENO" "SSL_set1_dnsname" "ac_cv_func_SSL_set1_dnsname"
|
||||
if test "x$ac_cv_func_SSL_set1_dnsname" = xyes
|
||||
then :
|
||||
printf "%s\n" "#define HAVE_SSL_SET1_DNSNAME 1" >>confdefs.h
|
||||
|
||||
fi
|
||||
ac_fn_c_check_func "$LINENO" "X509_get_key_usage" "ac_cv_func_X509_get_key_usage"
|
||||
if test "x$ac_cv_func_X509_get_key_usage" = xyes
|
||||
then :
|
||||
printf "%s\n" "#define HAVE_X509_GET_KEY_USAGE 1" >>confdefs.h
|
||||
|
||||
fi
|
||||
ac_fn_c_check_func "$LINENO" "ASN1_STRING_get0_data" "ac_cv_func_ASN1_STRING_get0_data"
|
||||
if test "x$ac_cv_func_ASN1_STRING_get0_data" = xyes
|
||||
then :
|
||||
printf "%s\n" "#define HAVE_ASN1_STRING_GET0_DATA 1" >>confdefs.h
|
||||
|
||||
fi
|
||||
ac_fn_c_check_func "$LINENO" "X509_VERIFY_PARAM_set1_host" "ac_cv_func_X509_VERIFY_PARAM_set1_host"
|
||||
if test "x$ac_cv_func_X509_VERIFY_PARAM_set1_host" = xyes
|
||||
@@ -21132,6 +21191,54 @@ then :
|
||||
|
||||
fi
|
||||
|
||||
ac_fn_c_check_func "$LINENO" "X509_NAME_get_text_by_NID" "ac_cv_func_X509_NAME_get_text_by_NID"
|
||||
if test "x$ac_cv_func_X509_NAME_get_text_by_NID" = xyes
|
||||
then :
|
||||
printf "%s\n" "#define HAVE_X509_NAME_GET_TEXT_BY_NID 1" >>confdefs.h
|
||||
|
||||
fi
|
||||
|
||||
if test $ac_cv_func_X509_NAME_get_text_by_NID = yes; then
|
||||
|
||||
|
||||
{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking if X509_NAME_get_text_by_NID is deprecated" >&5
|
||||
printf %s "checking if X509_NAME_get_text_by_NID is deprecated... " >&6; }
|
||||
cache=`echo X509_NAME_get_text_by_NID | sed 'y%.=/+-%___p_%'`
|
||||
if eval test \${cv_cc_deprecated_$cache+y}
|
||||
then :
|
||||
printf %s "(cached) " >&6
|
||||
else $as_nop
|
||||
|
||||
echo '
|
||||
#include "openssl/x509.h"
|
||||
' >conftest.c
|
||||
echo 'void f(void){
|
||||
(void)X509_NAME_get_text_by_NID(NULL, 0, NULL, 0); }' >>conftest.c
|
||||
if test -z "`$CC $CPPFLAGS $CFLAGS -c conftest.c 2>&1 | grep -e deprecated -e unavailable`"; then
|
||||
eval "cv_cc_deprecated_$cache=no"
|
||||
else
|
||||
eval "cv_cc_deprecated_$cache=yes"
|
||||
fi
|
||||
rm -f conftest conftest.o conftest.c
|
||||
|
||||
fi
|
||||
|
||||
if eval "test \"`echo '$cv_cc_deprecated_'$cache`\" = yes"; then
|
||||
{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: yes" >&5
|
||||
printf "%s\n" "yes" >&6; }
|
||||
|
||||
printf "%s\n" "#define DEPRECATED_X509_NAME_GET_TEXT_BY_NID 1" >>confdefs.h
|
||||
|
||||
:
|
||||
|
||||
else
|
||||
{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5
|
||||
printf "%s\n" "no" >&6; }
|
||||
:
|
||||
|
||||
fi
|
||||
|
||||
fi
|
||||
LIBS="$BAKLIBS"
|
||||
|
||||
ac_fn_check_decl "$LINENO" "SSL_COMP_get_compression_methods" "ac_cv_have_decl_SSL_COMP_get_compression_methods" "
|
||||
@@ -22638,6 +22745,24 @@ then :
|
||||
|
||||
printf "%s\n" "#define USE_NGTCP2_CRYPTO_OSSL 1" >>confdefs.h
|
||||
|
||||
ac_fn_check_decl "$LINENO" "ngtcp2_crypto_ossl_ctx_new" "ac_cv_have_decl_ngtcp2_crypto_ossl_ctx_new" "$ac_includes_default
|
||||
#include <ngtcp2/ngtcp2_crypto_ossl.h>
|
||||
|
||||
" "$ac_c_undeclared_builtin_options" "CFLAGS"
|
||||
if test "x$ac_cv_have_decl_ngtcp2_crypto_ossl_ctx_new" = xyes
|
||||
then :
|
||||
ac_have_decl=1
|
||||
else $as_nop
|
||||
ac_have_decl=0
|
||||
fi
|
||||
printf "%s\n" "#define HAVE_DECL_NGTCP2_CRYPTO_OSSL_CTX_NEW $ac_have_decl" >>confdefs.h
|
||||
if test $ac_have_decl = 1
|
||||
then :
|
||||
|
||||
else $as_nop
|
||||
as_fn_error $? "No declaration of ngtcp2_crypto_ossl_ctx_new in the ngtcp2_crypto_ossl header file. Perhaps the ngtcp2_crypto_ossl devel header files need to be installed." "$LINENO" 5
|
||||
fi
|
||||
|
||||
|
||||
else $as_nop
|
||||
|
||||
@@ -22817,6 +22942,13 @@ else $as_nop
|
||||
fi
|
||||
|
||||
done
|
||||
ac_fn_c_check_func "$LINENO" "SSL_set_quic_tls_early_data_enabled" "ac_cv_func_SSL_set_quic_tls_early_data_enabled"
|
||||
if test "x$ac_cv_func_SSL_set_quic_tls_early_data_enabled" = xyes
|
||||
then :
|
||||
printf "%s\n" "#define HAVE_SSL_SET_QUIC_TLS_EARLY_DATA_ENABLED 1" >>confdefs.h
|
||||
|
||||
fi
|
||||
|
||||
LIBS="$BAKLIBS"
|
||||
|
||||
ac_fn_c_check_type "$LINENO" "struct ngtcp2_version_cid" "ac_cv_type_struct_ngtcp2_version_cid" "$ac_includes_default
|
||||
@@ -22922,6 +23054,29 @@ printf "%s\n" "no" >&6; }
|
||||
fi
|
||||
rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext
|
||||
|
||||
ac_fn_check_decl "$LINENO" "CLOCK_MONOTONIC
|
||||
" "ac_cv_have_decl_CLOCK_MONOTONIC_________" "$ac_includes_default
|
||||
#ifdef TIME_WITH_SYS_TIME
|
||||
# include <sys/time.h>
|
||||
# include <time.h>
|
||||
#else
|
||||
# ifdef HAVE_SYS_TIME_H
|
||||
# include <sys/time.h>
|
||||
# else
|
||||
# include <time.h>
|
||||
# endif
|
||||
#endif
|
||||
|
||||
" "$ac_c_undeclared_builtin_options" "CFLAGS"
|
||||
if test "x$ac_cv_have_decl_CLOCK_MONOTONIC_________" = xyes
|
||||
then :
|
||||
|
||||
|
||||
else $as_nop
|
||||
as_fn_error $? "ngtcp2 for QUIC needs at least CLOCK_MONOTONIC on the system" "$LINENO" 5
|
||||
|
||||
fi
|
||||
|
||||
fi
|
||||
|
||||
# set static linking for uninstalled libraries if requested
|
||||
@@ -23756,6 +23911,12 @@ if test "x$ac_cv_func_glob" = xyes
|
||||
then :
|
||||
printf "%s\n" "#define HAVE_GLOB 1" >>confdefs.h
|
||||
|
||||
fi
|
||||
ac_fn_c_check_func "$LINENO" "fnmatch" "ac_cv_func_fnmatch"
|
||||
if test "x$ac_cv_func_fnmatch" = xyes
|
||||
then :
|
||||
printf "%s\n" "#define HAVE_FNMATCH 1" >>confdefs.h
|
||||
|
||||
fi
|
||||
ac_fn_c_check_func "$LINENO" "initgroups" "ac_cv_func_initgroups"
|
||||
if test "x$ac_cv_func_initgroups" = xyes
|
||||
@@ -25552,7 +25713,7 @@ printf "%s\n" "#define MAXSYSLOGMSGLEN 10240" >>confdefs.h
|
||||
|
||||
|
||||
|
||||
version=1.25.1
|
||||
version=1.26.2
|
||||
|
||||
{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for build time" >&5
|
||||
printf %s "checking for build time... " >&6; }
|
||||
@@ -26082,7 +26243,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.25.1, which was
|
||||
This file was extended by unbound $as_me 1.26.2, which was
|
||||
generated by GNU Autoconf 2.71. Invocation command line was
|
||||
|
||||
CONFIG_FILES = $CONFIG_FILES
|
||||
@@ -26150,7 +26311,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.25.1
|
||||
unbound config.status 1.26.2
|
||||
configured by $0, generated by GNU Autoconf 2.71,
|
||||
with options \\"\$ac_cs_config\\"
|
||||
|
||||
|
||||
+38
-7
@@ -11,15 +11,15 @@ sinclude(dnscrypt/dnscrypt.m4)
|
||||
|
||||
# must be numbers. ac_defun because of later processing
|
||||
m4_define([VERSION_MAJOR],[1])
|
||||
m4_define([VERSION_MINOR],[25])
|
||||
m4_define([VERSION_MICRO],[1])
|
||||
m4_define([VERSION_MINOR],[26])
|
||||
m4_define([VERSION_MICRO],[2])
|
||||
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=37
|
||||
LIBUNBOUND_REVISION=41
|
||||
LIBUNBOUND_AGE=1
|
||||
# 1.0.0 had 0:12:0
|
||||
# 1.0.1 had 0:13:0
|
||||
@@ -124,6 +124,10 @@ LIBUNBOUND_AGE=1
|
||||
# 1.24.2 had 9:35:1
|
||||
# 1.25.0 had 9:36:1
|
||||
# 1.25.1 had 9:37:1
|
||||
# 1.25.2 had 9:38:1
|
||||
# 1.26.0 had 9:39:1
|
||||
# 1.26.1 had 9:40:1
|
||||
# 1.26.2 had 9:41:1
|
||||
|
||||
# Current -- the number of the binary API that we're implementing
|
||||
# Revision -- which iteration of the implementation of the binary
|
||||
@@ -482,7 +486,7 @@ PKG_PROG_PKG_CONFIG
|
||||
fi
|
||||
|
||||
# Checks for header files.
|
||||
AC_CHECK_HEADERS([stdarg.h stdbool.h netinet/in.h netinet/tcp.h sys/param.h sys/select.h sys/socket.h sys/un.h sys/uio.h sys/resource.h arpa/inet.h syslog.h netdb.h sys/wait.h pwd.h glob.h grp.h login_cap.h winsock2.h ws2tcpip.h endian.h sys/endian.h libkern/OSByteOrder.h sys/ipc.h sys/shm.h ifaddrs.h poll.h],,, [AC_INCLUDES_DEFAULT])
|
||||
AC_CHECK_HEADERS([stdarg.h stdbool.h netinet/in.h netinet/tcp.h sys/param.h sys/select.h sys/socket.h sys/un.h sys/uio.h sys/resource.h arpa/inet.h syslog.h netdb.h sys/wait.h pwd.h glob.h fnmatch.h grp.h login_cap.h winsock2.h ws2tcpip.h endian.h sys/endian.h libkern/OSByteOrder.h sys/ipc.h sys/shm.h ifaddrs.h poll.h],,, [AC_INCLUDES_DEFAULT])
|
||||
# net/if.h portability for Darwin see:
|
||||
# https://www.gnu.org/software/autoconf/manual/autoconf-2.69/html_node/Header-Portability.html
|
||||
AC_CHECK_HEADERS([net/if.h],,, [
|
||||
@@ -1079,12 +1083,19 @@ else
|
||||
AC_MSG_RESULT([no])
|
||||
fi
|
||||
AC_CHECK_HEADERS([openssl/conf.h openssl/engine.h openssl/bn.h openssl/dh.h openssl/dsa.h openssl/rsa.h openssl/core_names.h openssl/param_build.h],,, [AC_INCLUDES_DEFAULT])
|
||||
AC_CHECK_FUNCS([OPENSSL_config EVP_sha1 EVP_sha256 EVP_sha512 FIPS_mode EVP_default_properties_is_fips_enabled EVP_MD_CTX_new OpenSSL_add_all_digests OPENSSL_init_crypto EVP_cleanup ENGINE_cleanup ERR_load_crypto_strings CRYPTO_cleanup_all_ex_data ERR_free_strings RAND_cleanup DSA_SIG_set0 EVP_dss1 EVP_DigestVerify EVP_aes_256_cbc EVP_EncryptInit_ex HMAC_Init_ex CRYPTO_THREADID_set_callback EVP_MAC_CTX_set_params OSSL_PARAM_BLD_new BIO_set_callback_ex])
|
||||
AC_CHECK_FUNCS([OPENSSL_config EVP_sha1 EVP_sha256 EVP_sha512 FIPS_mode EVP_default_properties_is_fips_enabled EVP_MD_CTX_new OpenSSL_add_all_digests OPENSSL_init_crypto EVP_cleanup ENGINE_cleanup ERR_load_crypto_strings CRYPTO_cleanup_all_ex_data ERR_free_strings RAND_cleanup DSA_SIG_set0 EVP_dss1 EVP_DigestVerify EVP_aes_256_cbc EVP_EncryptInit_ex HMAC_Init_ex CRYPTO_THREADID_set_callback EVP_MAC_CTX_set_params OSSL_PARAM_BLD_new BIO_set_callback_ex OPENSSL_cleanup])
|
||||
|
||||
# these check_funcs need -lssl
|
||||
BAKLIBS="$LIBS"
|
||||
LIBS="-lssl $LIBS"
|
||||
AC_CHECK_FUNCS([OPENSSL_init_ssl SSL_CTX_set_security_level SSL_set1_host SSL_get0_peername X509_VERIFY_PARAM_set1_host SSL_CTX_set_ciphersuites SSL_CTX_set_tlsext_ticket_key_evp_cb SSL_CTX_set_alpn_select_cb SSL_get0_alpn_selected SSL_CTX_set_alpn_protos SSL_get1_peer_certificate])
|
||||
AC_CHECK_FUNCS([OPENSSL_init_ssl SSL_CTX_set_security_level SSL_set1_host SSL_get0_peername SSL_set1_dnsname X509_get_key_usage ASN1_STRING_get0_data X509_VERIFY_PARAM_set1_host SSL_CTX_set_ciphersuites SSL_CTX_set_tlsext_ticket_key_evp_cb SSL_CTX_set_alpn_select_cb SSL_get0_alpn_selected SSL_CTX_set_alpn_protos SSL_get1_peer_certificate])
|
||||
AC_CHECK_FUNCS([X509_NAME_get_text_by_NID])
|
||||
if test $ac_cv_func_X509_NAME_get_text_by_NID = yes; then
|
||||
ACX_FUNC_DEPRECATED([X509_NAME_get_text_by_NID], [
|
||||
(void)X509_NAME_get_text_by_NID(NULL, 0, NULL, 0);], [
|
||||
#include "openssl/x509.h"
|
||||
])
|
||||
fi
|
||||
LIBS="$BAKLIBS"
|
||||
|
||||
AC_CHECK_DECLS([SSL_COMP_get_compression_methods,sk_SSL_COMP_pop_free,SSL_CTX_set_ecdh_auto,SSL_CTX_set_tmp_ecdh], [], [], [
|
||||
@@ -1703,6 +1714,9 @@ if test x_$withval = x_yes -o x_$withval != x_no; then
|
||||
AC_CHECK_LIB([ngtcp2_crypto_ossl], [ngtcp2_crypto_encrypt_cb], [
|
||||
LIBS="$LIBS -lngtcp2_crypto_ossl"
|
||||
AC_DEFINE(USE_NGTCP2_CRYPTO_OSSL, 1, [Define this to use ngtcp2_crypto_ossl.])
|
||||
AC_CHECK_DECLS([ngtcp2_crypto_ossl_ctx_new], [], [AC_MSG_ERROR([No declaration of ngtcp2_crypto_ossl_ctx_new in the ngtcp2_crypto_ossl header file. Perhaps the ngtcp2_crypto_ossl devel header files need to be installed.])], [AC_INCLUDES_DEFAULT
|
||||
#include <ngtcp2/ngtcp2_crypto_ossl.h>
|
||||
])
|
||||
], [
|
||||
AC_CHECK_LIB([ngtcp2_crypto_openssl], [ngtcp2_crypto_encrypt_cb], [ LIBS="$LIBS -lngtcp2_crypto_openssl" ], [
|
||||
AC_CHECK_LIB([ngtcp2_crypto_quictls], [ngtcp2_crypto_encrypt_cb], [ LIBS="$LIBS -lngtcp2_crypto_quictls" ])
|
||||
@@ -1714,6 +1728,7 @@ if test x_$withval = x_yes -o x_$withval != x_no; then
|
||||
BAKLIBS="$LIBS"
|
||||
LIBS="-lssl $LIBS"
|
||||
AC_CHECK_FUNCS([SSL_is_quic], [], [AC_MSG_ERROR([No QUIC support detected in OpenSSL. Need OpenSSL version with QUIC support to enable DNS over QUIC with libngtcp2.])])
|
||||
AC_CHECK_FUNCS([SSL_set_quic_tls_early_data_enabled])
|
||||
LIBS="$BAKLIBS"
|
||||
|
||||
AC_CHECK_TYPES([struct ngtcp2_version_cid, ngtcp2_encryption_level],,,[AC_INCLUDES_DEFAULT
|
||||
@@ -1735,6 +1750,22 @@ if test x_$withval = x_yes -o x_$withval != x_no; then
|
||||
AC_MSG_RESULT(no)
|
||||
])
|
||||
|
||||
AC_CHECK_DECL([CLOCK_MONOTONIC]
|
||||
, []
|
||||
, [AC_MSG_ERROR([ngtcp2 for QUIC needs at least CLOCK_MONOTONIC on the system])]
|
||||
, [AC_INCLUDES_DEFAULT
|
||||
#ifdef TIME_WITH_SYS_TIME
|
||||
# include <sys/time.h>
|
||||
# include <time.h>
|
||||
#else
|
||||
# ifdef HAVE_SYS_TIME_H
|
||||
# include <sys/time.h>
|
||||
# else
|
||||
# include <time.h>
|
||||
# endif
|
||||
#endif
|
||||
])
|
||||
|
||||
fi
|
||||
|
||||
# set static linking for uninstalled libraries if requested
|
||||
@@ -1911,7 +1942,7 @@ AC_LINK_IFELSE([AC_LANG_PROGRAM([
|
||||
AC_MSG_RESULT(no))
|
||||
|
||||
AC_SEARCH_LIBS([setusercontext], [util])
|
||||
AC_CHECK_FUNCS([tzset sigprocmask fcntl getpwnam endpwent getrlimit setrlimit setsid chroot kill chown sleep usleep random srandom recvmsg sendmsg writev socketpair glob initgroups strftime localtime_r setusercontext _beginthreadex endservent endprotoent fsync shmget accept4 getifaddrs if_nametoindex poll gettid])
|
||||
AC_CHECK_FUNCS([tzset sigprocmask fcntl getpwnam endpwent getrlimit setrlimit setsid chroot kill chown sleep usleep random srandom recvmsg sendmsg writev socketpair glob fnmatch initgroups strftime localtime_r setusercontext _beginthreadex endservent endprotoent fsync shmget accept4 getifaddrs if_nametoindex poll gettid])
|
||||
AC_CHECK_FUNCS([setresuid],,[AC_CHECK_FUNCS([setreuid])])
|
||||
AC_CHECK_FUNCS([setresgid],,[AC_CHECK_FUNCS([setregid])])
|
||||
|
||||
|
||||
+3
-3
@@ -99,7 +99,7 @@ static void
|
||||
dump_rrset_line(struct config_strlist_head* txt, struct ub_packed_rrset_key* k,
|
||||
time_t now, size_t i)
|
||||
{
|
||||
char s[65535];
|
||||
char s[65535*4+2048];
|
||||
if(!packed_rr_to_string(k, i, now, s, sizeof(s))) {
|
||||
spool_txt_string(txt, "BADRR\n");
|
||||
return;
|
||||
@@ -455,7 +455,7 @@ load_rr(RES* ssl, sldns_buffer* buf, struct regional* region,
|
||||
/* read the line */
|
||||
if(!ssl_read_buf(ssl, buf))
|
||||
return 0;
|
||||
if(strncmp((char*)sldns_buffer_begin(buf), "BADRR\n", 6) == 0) {
|
||||
if(strcmp((char*)sldns_buffer_begin(buf), "BADRR") == 0) {
|
||||
*go_on = 0;
|
||||
return 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;
|
||||
|
||||
+51
-15
@@ -79,12 +79,14 @@
|
||||
#include "util/tcp_conn_limit.h"
|
||||
#include "util/edns.h"
|
||||
#include "services/listen_dnsport.h"
|
||||
#include "services/outside_network.h"
|
||||
#include "services/cache/rrset.h"
|
||||
#include "services/cache/infra.h"
|
||||
#include "services/localzone.h"
|
||||
#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"
|
||||
@@ -216,7 +218,8 @@ setup_listen_sslctx(void** ctx, int is_dot, int is_doh,
|
||||
(cfg->tls_session_ticket_keys.first &&
|
||||
cfg->tls_session_ticket_keys.first->str[0] != 0),
|
||||
is_dot, is_doh, cfg->tls_protocols))) {
|
||||
fatal_exit("could not set up listen SSL_CTX");
|
||||
log_err("could not set up listen SSL_CTX");
|
||||
*ctx = NULL;
|
||||
}
|
||||
}
|
||||
#endif /* HAVE_SSL */
|
||||
@@ -258,7 +261,8 @@ void* daemon_setup_listen_quic_sslctx(struct daemon* daemon,
|
||||
pem += strlen(chroot);
|
||||
|
||||
if(!(ctx = quic_sslctx_create(key, pem, NULL))) {
|
||||
fatal_exit("could not set up quic SSL_CTX");
|
||||
log_err("could not set up quic SSL_CTX");
|
||||
return NULL;
|
||||
}
|
||||
return ctx;
|
||||
}
|
||||
@@ -276,8 +280,10 @@ void* daemon_setup_connect_dot_sslctx(struct daemon* daemon,
|
||||
bundle += strlen(chroot);
|
||||
|
||||
if(!(ctx = connect_sslctx_create(NULL, NULL, bundle,
|
||||
cfg->tls_win_cert)))
|
||||
fatal_exit("could not set up connect SSL_CTX");
|
||||
cfg->tls_win_cert))) {
|
||||
log_err("could not set up connect SSL_CTX");
|
||||
return NULL;
|
||||
}
|
||||
return ctx;
|
||||
}
|
||||
#endif /* HAVE_SSL */
|
||||
@@ -307,16 +313,22 @@ daemon_setup_sslctxs(struct daemon* daemon, struct config_file* cfg)
|
||||
}
|
||||
daemon->listen_dot_sslctx = daemon_setup_listen_dot_sslctx(
|
||||
daemon, cfg);
|
||||
if(!daemon->listen_dot_sslctx)
|
||||
fatal_exit("Could not set up listen dot sslctx");
|
||||
#ifdef HAVE_NGHTTP2_NGHTTP2_H
|
||||
if(cfg_has_https(cfg)) {
|
||||
daemon->listen_doh_sslctx =
|
||||
daemon_setup_listen_doh_sslctx(daemon, cfg);
|
||||
if(!daemon->listen_doh_sslctx)
|
||||
fatal_exit("Could not set up listen doh sslctx");
|
||||
}
|
||||
#endif
|
||||
#ifdef HAVE_NGTCP2
|
||||
if(cfg_has_quic(cfg)) {
|
||||
daemon->listen_quic_sslctx =
|
||||
daemon_setup_listen_quic_sslctx(daemon, cfg);
|
||||
if(!daemon->listen_quic_sslctx)
|
||||
fatal_exit("Could not set up listen quic sslctx");
|
||||
}
|
||||
#endif /* HAVE_NGTCP2 */
|
||||
|
||||
@@ -349,6 +361,8 @@ daemon_setup_sslctxs(struct daemon* daemon, struct config_file* cfg)
|
||||
}
|
||||
daemon->connect_dot_sslctx = daemon_setup_connect_dot_sslctx(
|
||||
daemon, cfg);
|
||||
if(!daemon->connect_dot_sslctx)
|
||||
fatal_exit("could not setup connect dot sslctx");
|
||||
#else /* HAVE_SSL */
|
||||
(void)daemon;(void)cfg;
|
||||
#endif /* HAVE_SSL */
|
||||
@@ -577,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;
|
||||
}
|
||||
|
||||
@@ -813,6 +838,10 @@ daemon_create_workers(struct daemon* daemon)
|
||||
fatal_exit("out of memory during daemon init");
|
||||
numport = daemon_get_shufport(daemon, shufport);
|
||||
verbose(VERB_ALGO, "total of %d outgoing ports available", numport);
|
||||
if(!(daemon->shared_ports = shared_ports_create(daemon->cfg->out_ifs,
|
||||
daemon->cfg->num_out_ifs, daemon->cfg->do_ip4,
|
||||
daemon->cfg->do_ip6, shufport, numport)))
|
||||
fatal_exit("could not setup shared ports: out of memory");
|
||||
|
||||
#ifdef HAVE_NGTCP2
|
||||
if (cfg_has_quic(daemon->cfg)) {
|
||||
@@ -843,10 +872,7 @@ daemon_create_workers(struct daemon* daemon)
|
||||
#endif
|
||||
}
|
||||
for(i=0; i<daemon->num; i++) {
|
||||
if(!(daemon->workers[i] = worker_create(daemon, i,
|
||||
shufport+numport*i/daemon->num,
|
||||
numport*(i+1)/daemon->num - numport*i/daemon->num)))
|
||||
/* the above is not ports/numthr, due to rounding */
|
||||
if(!(daemon->workers[i] = worker_create(daemon, i)))
|
||||
fatal_exit("could not create worker");
|
||||
}
|
||||
/* create per-worker alloc caches if not reusing existing ones. */
|
||||
@@ -919,13 +945,14 @@ thread_start(void* arg)
|
||||
{
|
||||
struct worker* worker = (struct worker*)arg;
|
||||
int port_num = 0;
|
||||
log_assert(worker->thr_id);
|
||||
set_log_thread_id(worker, worker->daemon->cfg);
|
||||
{
|
||||
char name[16]; /* seems to be the safest size between
|
||||
different OSes */
|
||||
snprintf(name, sizeof(name), "unbound/%u", worker->thread_num);
|
||||
ub_thread_setname(worker->thr_id, name);
|
||||
/* worker->thr_id can be written to after the thread was made
|
||||
* by the creating thread, so this uses pthread_self. */
|
||||
ub_thread_setname(ub_thread_self(), name);
|
||||
}
|
||||
ub_thread_blocksigs();
|
||||
#ifdef THREADS_DISABLED
|
||||
@@ -940,8 +967,9 @@ thread_start(void* arg)
|
||||
port_num = 0;
|
||||
#endif
|
||||
if(!worker_init(worker, worker->daemon->cfg,
|
||||
worker->daemon->ports[port_num], 0))
|
||||
worker->daemon->ports[port_num], 0)) {
|
||||
fatal_exit("Could not initialize thread");
|
||||
}
|
||||
|
||||
worker_work(worker);
|
||||
return NULL;
|
||||
@@ -1103,8 +1131,9 @@ daemon_fork(struct daemon* daemon)
|
||||
|
||||
#if defined(HAVE_EV_LOOP) || defined(HAVE_EV_DEFAULT_LOOP)
|
||||
/* in libev the first inited base gets signals */
|
||||
if(!worker_init(daemon->workers[0], daemon->cfg, daemon->ports[0], 1))
|
||||
if(!worker_init(daemon->workers[0], daemon->cfg, daemon->ports[0], 1)) {
|
||||
fatal_exit("Could not initialize main thread");
|
||||
}
|
||||
#endif
|
||||
|
||||
/* Now create the threads and init the workers.
|
||||
@@ -1117,8 +1146,9 @@ daemon_fork(struct daemon* daemon)
|
||||
*/
|
||||
#if !(defined(HAVE_EV_LOOP) || defined(HAVE_EV_DEFAULT_LOOP))
|
||||
/* libevent has the last inited base get signals (or any base) */
|
||||
if(!worker_init(daemon->workers[0], daemon->cfg, daemon->ports[0], 1))
|
||||
if(!worker_init(daemon->workers[0], daemon->cfg, daemon->ports[0], 1)) {
|
||||
fatal_exit("Could not initialize main thread");
|
||||
}
|
||||
#endif
|
||||
signal_handling_playback(daemon->workers[0]);
|
||||
|
||||
@@ -1146,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);
|
||||
@@ -1162,7 +1193,6 @@ daemon_cleanup(struct daemon* daemon)
|
||||
/* before stopping main worker, handle signals ourselves, so we
|
||||
don't die on multiple reload signals for example. */
|
||||
signal_handling_record();
|
||||
log_thread_set(NULL);
|
||||
/* clean up caches because
|
||||
* a) RRset IDs will be recycled after a reload, causing collisions
|
||||
* b) validation config can change, thus rrset, msg, keycache clear
|
||||
@@ -1204,6 +1234,8 @@ daemon_cleanup(struct daemon* daemon)
|
||||
if(!daemon->reuse_cache || daemon->need_to_exit)
|
||||
daemon_clear_allocs(daemon);
|
||||
daemon->num = 0;
|
||||
shared_ports_delete(daemon->shared_ports);
|
||||
daemon->shared_ports = NULL;
|
||||
#ifdef USE_DNSTAP
|
||||
dt_delete(daemon->dtenv);
|
||||
daemon->dtenv = NULL;
|
||||
@@ -1243,6 +1275,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);
|
||||
@@ -1266,7 +1299,7 @@ daemon_delete(struct daemon* daemon)
|
||||
# if HAVE_DECL_SSL_COMP_GET_COMPRESSION_METHODS && HAVE_DECL_SK_SSL_COMP_POP_FREE
|
||||
# ifndef S_SPLINT_S
|
||||
# if OPENSSL_VERSION_NUMBER < 0x10100000
|
||||
sk_SSL_COMP_pop_free(comp_meth, (void(*)())CRYPTO_free);
|
||||
sk_SSL_COMP_pop_free(comp_meth, (void(*)(SSL_COMP*))CRYPTO_free);
|
||||
# endif
|
||||
# endif
|
||||
# endif
|
||||
@@ -1289,6 +1322,9 @@ daemon_delete(struct daemon* daemon)
|
||||
# if defined(HAVE_SSL) && defined(OPENSSL_THREADS) && !defined(THREADS_DISABLED)
|
||||
ub_openssl_lock_delete();
|
||||
# endif
|
||||
#ifdef HAVE_OPENSSL_CLEANUP
|
||||
OPENSSL_cleanup();
|
||||
#endif
|
||||
#ifndef HAVE_ARC4RANDOM
|
||||
_ARC4_LOCK_DESTROY();
|
||||
#endif
|
||||
|
||||
@@ -62,6 +62,8 @@ 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"
|
||||
#ifdef USE_DNSTAP
|
||||
@@ -97,6 +99,8 @@ struct daemon {
|
||||
int rc_port;
|
||||
/** listening ports for remote control */
|
||||
struct listen_port* rc_ports;
|
||||
/** the shared ports structure, with random ports numbers. */
|
||||
struct shared_ports* shared_ports;
|
||||
/** remote control connections management (for first worker) */
|
||||
struct daemon_remote* rc;
|
||||
/** ssl context for listening to dnstcp over ssl */
|
||||
@@ -188,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;
|
||||
};
|
||||
|
||||
/**
|
||||
|
||||
+301
-386
@@ -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
|
||||
@@ -307,7 +305,7 @@ add_open(const char* ip, int nr, struct listen_port** list, int noproto_is_err,
|
||||
#endif
|
||||
}
|
||||
} else {
|
||||
char* s = strchr(ip, '@');
|
||||
const char* s = strchr(ip, '@');
|
||||
char newif[128];
|
||||
if(s) {
|
||||
/* override port with ifspec@port */
|
||||
@@ -1533,18 +1531,95 @@ do_datas_add(struct daemon_remote* rc, RES* ssl, struct worker* worker)
|
||||
(void)ssl_printf(ssl, "added %d datas\n", num);
|
||||
}
|
||||
|
||||
static int
|
||||
perform_data_remove_rr(RES* ssl, struct local_zones* local_zones,
|
||||
uint8_t* rr, size_t len, size_t dname_len, char *arg)
|
||||
{
|
||||
uint16_t rr_class, rr_type;
|
||||
int labs;
|
||||
struct local_zone* z;
|
||||
struct local_data* ld;
|
||||
uint8_t *rdata;
|
||||
size_t rdata_len, index;
|
||||
struct packed_rrset_data* d;
|
||||
struct local_rrset* p;
|
||||
|
||||
rdata = sldns_wirerr_get_rdatawl(rr, len, dname_len);
|
||||
rdata_len = ((size_t)sldns_wirerr_get_rdatalen(rr, len, dname_len))+2;
|
||||
|
||||
labs = dname_count_labels(rr);
|
||||
|
||||
rr_class = sldns_wirerr_get_class(rr, len, dname_len);
|
||||
rr_type = sldns_wirerr_get_type(rr, len, dname_len);
|
||||
|
||||
z = local_zones_lookup(local_zones, rr, dname_len,
|
||||
labs, rr_class, rr_type, 1);
|
||||
if (!z) {
|
||||
ssl_printf(ssl, "error no zone for rr %s\n", arg);
|
||||
return 0;
|
||||
}
|
||||
|
||||
ld = local_zone_find_data(z, rr, dname_len, labs);
|
||||
if (!ld) {
|
||||
ssl_printf(ssl, "error no local data for rr %s\n", arg);
|
||||
return 0;
|
||||
}
|
||||
|
||||
p = ld->rrsets;
|
||||
while (p && ntohs(p->rrset->rk.type) != rr_type) {
|
||||
p = p->next;
|
||||
}
|
||||
|
||||
if (!p) {
|
||||
ssl_printf(ssl, "error no rrset for rr %s\n", arg);
|
||||
return 0;
|
||||
}
|
||||
|
||||
d = (struct packed_rrset_data*)p->rrset->entry.data;
|
||||
if (!packed_rrset_find_rr(d, rdata, rdata_len, &index)) {
|
||||
ssl_printf(ssl, "error rr %s not found in rrset\n", arg);
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (!local_rrset_remove_rr(d, index)) {
|
||||
ssl_printf(ssl, "error unable to delete rr %s\n", arg);
|
||||
return 0;
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
/** Remove RR data */
|
||||
static int
|
||||
perform_data_remove(RES* ssl, struct local_zones* zones, char* arg)
|
||||
{
|
||||
uint8_t* nm;
|
||||
int nmlabs;
|
||||
size_t nmlen;
|
||||
if(!parse_arg_name(ssl, arg, &nm, &nmlen, &nmlabs))
|
||||
uint8_t rr[LDNS_RR_BUF_SIZE], *nm;
|
||||
size_t len = sizeof(rr);
|
||||
int status, nmlabs;
|
||||
size_t nmlen, dname_len;
|
||||
|
||||
/* try to parse as a rr first */
|
||||
status = sldns_str2wire_rr_buf(arg, rr, &len, &dname_len, 3600,
|
||||
NULL, 0, NULL, 0);
|
||||
|
||||
/* try to parse as a domain name second */
|
||||
if (status != 0) {
|
||||
if (parse_arg_name(ssl, arg, &nm, &nmlen, &nmlabs)) {
|
||||
local_zones_del_data(zones, nm,
|
||||
nmlen, nmlabs, LDNS_RR_CLASS_IN);
|
||||
free(nm);
|
||||
return 1;
|
||||
}
|
||||
ssl_printf(ssl, "error cannot parse rr %s at %d: %s\n", arg,
|
||||
LDNS_WIREPARSE_OFFSET(status),
|
||||
sldns_get_errorstr_parse(status));
|
||||
return 0;
|
||||
local_zones_del_data(zones, nm,
|
||||
nmlen, nmlabs, LDNS_RR_CLASS_IN);
|
||||
free(nm);
|
||||
}
|
||||
|
||||
/* handle the rr case */
|
||||
if (!perform_data_remove_rr(ssl, zones, rr, len, dname_len, arg))
|
||||
return 0;
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
@@ -1658,6 +1733,14 @@ do_view_data_add(RES* ssl, struct worker* worker, char* arg)
|
||||
ssl_printf(ssl,"error out of memory\n");
|
||||
return;
|
||||
}
|
||||
if(!v->isfirst) {
|
||||
/* Global local-zone is not used for this view,
|
||||
* therefore add defaults to this view-specific
|
||||
* local-zone. */
|
||||
struct config_file lz_cfg;
|
||||
memset(&lz_cfg, 0, sizeof(lz_cfg));
|
||||
local_zone_enter_defaults(v->local_zones, &lz_cfg);
|
||||
}
|
||||
}
|
||||
do_data_add(ssl, v->local_zones, arg2);
|
||||
lock_rw_unlock(&v->lock);
|
||||
@@ -1683,6 +1766,14 @@ do_view_datas_add(struct daemon_remote* rc, RES* ssl, struct worker* worker,
|
||||
ssl_printf(ssl,"error out of memory\n");
|
||||
return;
|
||||
}
|
||||
if(!v->isfirst) {
|
||||
/* Global local-zone is not used for this view,
|
||||
* therefore add defaults to this view-specific
|
||||
* local-zone. */
|
||||
struct config_file lz_cfg;
|
||||
memset(&lz_cfg, 0, sizeof(lz_cfg));
|
||||
local_zone_enter_defaults(v->local_zones, &lz_cfg);
|
||||
}
|
||||
}
|
||||
/* put the view name in the command buf */
|
||||
(void)snprintf(buf+strlen(buf), sizeof(buf)-strlen(buf), "%s ", arg);
|
||||
@@ -2299,6 +2390,9 @@ zone_del_rrset(struct lruhash_entry* e, void* arg)
|
||||
(struct packed_rrset_data*)e->data;
|
||||
if(d->ttl > inf->expired) {
|
||||
d->ttl = inf->expired;
|
||||
if(d->ttl_add > inf->expired)
|
||||
d->ttl_add = inf->expired; /* for 0TTL rrsets,
|
||||
means that d->ttl_add <= d->ttl */
|
||||
inf->num_rrsets++;
|
||||
}
|
||||
}
|
||||
@@ -2585,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;
|
||||
@@ -2600,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;
|
||||
}
|
||||
@@ -3222,6 +3335,10 @@ do_auth_zone_reload(RES* ssl, struct worker* worker, char* arg)
|
||||
return;
|
||||
}
|
||||
if(!auth_zone_read_zonefile(z, worker->env.cfg)) {
|
||||
/* The old tree was already cleared. Do not answer from the
|
||||
* failed load. */
|
||||
z->zone_expired = 1;
|
||||
auth_zone_clear_data(z);
|
||||
lock_rw_unlock(&z->lock);
|
||||
if(xfr) {
|
||||
lock_basic_unlock(&xfr->lock);
|
||||
@@ -3233,6 +3350,7 @@ do_auth_zone_reload(RES* ssl, struct worker* worker, char* arg)
|
||||
z->zone_expired = 0;
|
||||
if(xfr) {
|
||||
xfr->zone_expired = 0;
|
||||
xfr->num_ixfrs = 0;
|
||||
if(!xfr_find_soa(z, xfr)) {
|
||||
if(z->data.count == 0) {
|
||||
lock_rw_unlock(&z->lock);
|
||||
@@ -4346,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)
|
||||
@@ -4925,6 +4957,74 @@ fr_check_changed_cfg_str2list(struct config_str2list* cmp1,
|
||||
}
|
||||
}
|
||||
|
||||
/** fast reload thread, check if config str3list has changed. */
|
||||
#define FR_CHECK_CHANGED_CFG_STR3LIST(desc, var, buff) do { \
|
||||
fr_check_changed_cfg_str3list(cfg->var, newcfg->var, desc, buff,\
|
||||
sizeof(buff)); \
|
||||
} while(0);
|
||||
static void
|
||||
fr_check_changed_cfg_str3list(struct config_str3list* cmp1,
|
||||
struct config_str3list* cmp2, const char* desc, char* str, size_t len)
|
||||
{
|
||||
struct config_str3list* p1 = cmp1, *p2 = cmp2;
|
||||
while(p1 && p2) {
|
||||
if((!p1->str && p2->str) ||
|
||||
(p1->str && !p2->str) ||
|
||||
(p1->str && p2->str && strcmp(p1->str, p2->str) != 0)) {
|
||||
/* The str3list is different. */
|
||||
fr_add_incompatible_option(desc, str, len);
|
||||
return;
|
||||
}
|
||||
if((!p1->str2 && p2->str2) ||
|
||||
(p1->str2 && !p2->str2) ||
|
||||
(p1->str2 && p2->str2 &&
|
||||
strcmp(p1->str2, p2->str2) != 0)) {
|
||||
/* The str3list is different. */
|
||||
fr_add_incompatible_option(desc, str, len);
|
||||
return;
|
||||
}
|
||||
if((!p1->str3 && p2->str3) ||
|
||||
(p1->str3 && !p2->str3) ||
|
||||
(p1->str3 && p2->str3 &&
|
||||
strcmp(p1->str3, p2->str3) != 0)) {
|
||||
/* The str3list is different. */
|
||||
fr_add_incompatible_option(desc, str, len);
|
||||
return;
|
||||
}
|
||||
p1 = p1->next;
|
||||
p2 = p2->next;
|
||||
}
|
||||
if((!p1 && p2) || (p1 && !p2)) {
|
||||
fr_add_incompatible_option(desc, str, len);
|
||||
}
|
||||
}
|
||||
|
||||
/** fast reload thread, check tag datas. */
|
||||
static int
|
||||
fr_check_tag_datas(struct fast_reload_thread* fr, struct config_file* newcfg)
|
||||
{
|
||||
char changed_str[1024];
|
||||
struct config_file* cfg = fr->worker->env.cfg;
|
||||
changed_str[0]=0;
|
||||
|
||||
/* Check for tag_datas in acl_addr. */
|
||||
FR_CHECK_CHANGED_CFG_STR3LIST("interface-tag-data", interface_tag_datas, changed_str);
|
||||
FR_CHECK_CHANGED_CFG_STR3LIST("access-control-tag-data", acl_tag_datas, changed_str);
|
||||
|
||||
if(changed_str[0] != 0) {
|
||||
if(fr->fr_drop_mesh)
|
||||
return 1; /* already dropping queries */
|
||||
fr->fr_drop_mesh = 1;
|
||||
fr->worker->daemon->fast_reload_drop_mesh = fr->fr_drop_mesh;
|
||||
if(!fr_output_printf(fr, "recursion referenced data has changed, with: '%s"
|
||||
"', and the queries have to be dropped"
|
||||
", setting '+d'\n", changed_str))
|
||||
return 0;
|
||||
fr_send_notification(fr, fast_reload_notification_printout);
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
/** fast reload thread, check compatible config items */
|
||||
static int
|
||||
fr_check_compat_cfg(struct fast_reload_thread* fr, struct config_file* newcfg)
|
||||
@@ -5461,6 +5561,23 @@ xfr_masterlist_equal(struct auth_master* list1, struct auth_master* list2)
|
||||
return 0;
|
||||
}
|
||||
|
||||
/** See if configuration has changed. */
|
||||
static int
|
||||
xfr_config_equal(struct auth_xfer* xfr1, struct auth_xfer* xfr2)
|
||||
{
|
||||
if(xfr1 == NULL && xfr2 == NULL)
|
||||
return 1;
|
||||
if(xfr1 == NULL && xfr2 != NULL)
|
||||
return 0;
|
||||
if(xfr1 != NULL && xfr2 == NULL)
|
||||
return 0;
|
||||
if(xfr1->max_transfer_size != xfr2->max_transfer_size)
|
||||
return 0;
|
||||
if(xfr1->max_transfer_time != xfr2->max_transfer_time)
|
||||
return 0;
|
||||
return 1;
|
||||
}
|
||||
|
||||
/** See if the list of masters has changed. */
|
||||
static int
|
||||
xfr_masters_equal(struct auth_xfer* xfr1, struct auth_xfer* xfr2)
|
||||
@@ -5549,8 +5666,31 @@ auth_zones_check_changes(struct fast_reload_thread* fr,
|
||||
&old_serial)!=0);
|
||||
have_new = (auth_zone_get_serial(new_z,
|
||||
&new_serial)!=0);
|
||||
/* A change in primaries, also means it is different
|
||||
* and the change makes it fire new transfers, from
|
||||
* the new primaries. */
|
||||
/* Treat as changed when the old zone has an
|
||||
* outstanding ZONEMD DS/DNSKEY mesh callback.
|
||||
* This will make the worker pickup change code
|
||||
* remove the mesh callback, before the old zone is
|
||||
* deleted. Also it makes a new zonemd lookup.
|
||||
* The new lookup is needed, because the new zone
|
||||
* entry needs to have a valid zonemd result,
|
||||
* and if that is bad, needs to be invalidated.
|
||||
* Also if there is a race event where the
|
||||
* outstanding callback makes the zone invalid,
|
||||
* before fast-reload completes, the change makes
|
||||
* the new zone entry have a new zonemd lookup,
|
||||
* to then invalidate that new zone.
|
||||
* There is also a brief operational window at
|
||||
* program start when a zonemd has to be looked
|
||||
* up on-line, where the zone is operational.
|
||||
* And this copies that for such a race event.
|
||||
*/
|
||||
if(have_old != have_new || old_serial != new_serial
|
||||
|| !xfr_masters_equal(old_xfr, new_xfr)) {
|
||||
|| !xfr_masters_equal(old_xfr, new_xfr)
|
||||
|| !xfr_config_equal(old_xfr, new_xfr)
|
||||
|| old_z->zonemd_callback_env != NULL) {
|
||||
/* The zone has been changed. */
|
||||
if(!fr_add_auth_zone_change(fr, old_z, new_z,
|
||||
0, 0, 1)) {
|
||||
@@ -5623,6 +5763,8 @@ ct_create_sslctxs(struct fast_reload_construct* ct,
|
||||
/* Leave listen ctxs and file str at NULL */
|
||||
ct->connect_dot_sslctx = daemon_setup_connect_dot_sslctx(
|
||||
daemon, newcfg);
|
||||
if(!ct->connect_dot_sslctx)
|
||||
return 0;
|
||||
return 1;
|
||||
}
|
||||
|
||||
@@ -5632,20 +5774,28 @@ ct_create_sslctxs(struct fast_reload_construct* ct,
|
||||
pem += strlen(chroot);
|
||||
|
||||
ct->listen_dot_sslctx = daemon_setup_listen_dot_sslctx(daemon, newcfg);
|
||||
if(!ct->listen_dot_sslctx)
|
||||
return 0;
|
||||
#ifdef HAVE_NGHTTP2_NGHTTP2_H
|
||||
if(cfg_has_https(newcfg)) {
|
||||
ct->listen_doh_sslctx = daemon_setup_listen_doh_sslctx(
|
||||
daemon, newcfg);
|
||||
if(!ct->listen_doh_sslctx)
|
||||
return 0;
|
||||
}
|
||||
#endif
|
||||
#ifdef HAVE_NGTCP2
|
||||
if(cfg_has_quic(newcfg)) {
|
||||
ct->listen_quic_sslctx = daemon_setup_listen_quic_sslctx(
|
||||
daemon, newcfg);
|
||||
if(!ct->listen_quic_sslctx)
|
||||
return 0;
|
||||
}
|
||||
#endif /* HAVE_NGTCP2 */
|
||||
ct->connect_dot_sslctx = daemon_setup_connect_dot_sslctx(daemon,
|
||||
newcfg);
|
||||
if(!ct->connect_dot_sslctx)
|
||||
return 0;
|
||||
|
||||
/* Store mtime and names */
|
||||
ct->ssl_service_key = strdup(newcfg->ssl_service_key);
|
||||
@@ -6127,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);
|
||||
@@ -6135,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);
|
||||
@@ -6371,6 +6523,8 @@ fr_atomic_copy_cfg(struct config_file* oldcfg, struct config_file* cfg,
|
||||
COPY_VAR_ptr(ipset_name_v6);
|
||||
#endif
|
||||
COPY_VAR_int(ede);
|
||||
COPY_VAR_int(val_validation_attempts);
|
||||
COPY_VAR_int(val_hash_attempts);
|
||||
COPY_VAR_int(iter_scrub_ns);
|
||||
COPY_VAR_int(iter_scrub_cname);
|
||||
COPY_VAR_int(iter_scrub_rrsig);
|
||||
@@ -6615,9 +6769,12 @@ fr_reload_config(struct fast_reload_thread* fr, struct config_file* newcfg,
|
||||
}
|
||||
#ifdef USE_DNSTAP
|
||||
if(env->cfg->dnstap) {
|
||||
if(!fr->fr_nopause)
|
||||
dt_apply_cfg(daemon->dtenv, env->cfg);
|
||||
else dt_apply_logcfg(daemon->dtenv, env->cfg);
|
||||
if(!fr->fr_nopause) {
|
||||
if(!dt_apply_cfg(daemon->dtenv, env->cfg))
|
||||
log_warn("fast_reload: dnstap identity/version metadata not updated due to allocation failure");
|
||||
} else {
|
||||
dt_apply_logcfg(daemon->dtenv, env->cfg);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
fr_adjust_cache(env, ct->oldcfg);
|
||||
@@ -6757,6 +6914,10 @@ fr_load_config(struct fast_reload_thread* fr, struct timeval* time_read,
|
||||
config_delete(newcfg);
|
||||
return 0;
|
||||
}
|
||||
if(!fr_check_tag_datas(fr, newcfg)) {
|
||||
config_delete(newcfg);
|
||||
return 0;
|
||||
}
|
||||
if(!fr_check_compat_cfg(fr, newcfg)) {
|
||||
config_delete(newcfg);
|
||||
return 0;
|
||||
@@ -6848,7 +7009,7 @@ static void* fast_reload_thread_main(void* arg)
|
||||
#endif
|
||||
log_thread_set(&fast_reload_thread->threadnum);
|
||||
|
||||
ub_thread_setname(fast_reload_thread->tid, name);
|
||||
ub_thread_setname(ub_thread_self(), name);
|
||||
(void)name; /* When setname is not defined, ignore the name variable. */
|
||||
|
||||
verbose(VERB_ALGO, "start fast reload thread");
|
||||
@@ -6908,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,
|
||||
@@ -7564,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;
|
||||
@@ -7571,7 +7459,8 @@ auth_zone_zonemd_stop_lookup(struct auth_zone* z, struct mesh_area* mesh)
|
||||
qinfo.local_alias = NULL;
|
||||
|
||||
mesh_remove_callback(mesh, &qinfo, qflags,
|
||||
&auth_zonemd_dnskey_lookup_callback, z);
|
||||
&auth_zonemd_dnskey_lookup_callback, z,
|
||||
z->zonemd_callback_unique_info);
|
||||
}
|
||||
|
||||
/** Pick up the auth zone locks. */
|
||||
@@ -7644,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);
|
||||
}
|
||||
|
||||
@@ -7680,6 +7571,9 @@ auth_xfr_pickup_config(struct auth_xfer* loadxfr, struct auth_xfer* xfr)
|
||||
log_assert(loadxfr->namelabs == xfr->namelabs);
|
||||
log_assert(loadxfr->dclass == xfr->dclass);
|
||||
|
||||
xfr->max_transfer_size = loadxfr->max_transfer_size;
|
||||
xfr->max_transfer_time = loadxfr->max_transfer_time;
|
||||
|
||||
/* The lists can be swapped in, the other xfr struct will be deleted
|
||||
* afterwards. */
|
||||
probe_masters = xfr->task_probe->masters;
|
||||
@@ -7704,6 +7598,16 @@ fr_worker_auth_add(struct worker* worker, struct fast_reload_auth_change* item,
|
||||
/* The xfr item needs to be created. The auth zones lock
|
||||
* is held to make this possible. */
|
||||
xfr = auth_xfer_create(worker->env.auth_zones, item->new_z);
|
||||
if(!xfr) {
|
||||
log_err("out of memory in fr_worker_auth_add");
|
||||
lock_rw_unlock(&item->new_z->lock);
|
||||
lock_rw_unlock(&worker->env.auth_zones->lock);
|
||||
lock_rw_unlock(&worker->daemon->fast_reload_thread->old_auth_zones->lock);
|
||||
if(loadxfr) {
|
||||
lock_basic_unlock(&loadxfr->lock);
|
||||
}
|
||||
return;
|
||||
}
|
||||
auth_xfr_pickup_config(loadxfr, xfr);
|
||||
/* Serial information is copied into the xfr struct. */
|
||||
if(!xfr_find_soa(item->new_z, xfr)) {
|
||||
@@ -7773,6 +7677,17 @@ fr_worker_auth_cha(struct worker* worker, struct fast_reload_auth_change* item)
|
||||
} else if(loadxfr && !xfr) {
|
||||
/* Create the xfr. */
|
||||
xfr = auth_xfer_create(worker->env.auth_zones, item->new_z);
|
||||
if(!xfr) {
|
||||
log_err("out of memory in fr_worker_auth_cha");
|
||||
lock_rw_unlock(&item->new_z->lock);
|
||||
lock_rw_unlock(&item->old_z->lock);
|
||||
lock_rw_unlock(&worker->daemon->fast_reload_thread->old_auth_zones->lock);
|
||||
lock_rw_unlock(&worker->env.auth_zones->lock);
|
||||
if(loadxfr) {
|
||||
lock_basic_unlock(&loadxfr->lock);
|
||||
}
|
||||
return;
|
||||
}
|
||||
auth_xfr_pickup_config(loadxfr, xfr);
|
||||
item->new_z->zone_is_slave = 1;
|
||||
}
|
||||
|
||||
+1
-7
@@ -49,6 +49,7 @@
|
||||
#include <openssl/ssl.h>
|
||||
#endif
|
||||
#include "util/locks.h"
|
||||
#include "libunbound/remote.h"
|
||||
struct config_file;
|
||||
struct listen_list;
|
||||
struct listen_port;
|
||||
@@ -365,13 +366,6 @@ void fast_reload_thread_start(RES* ssl, struct worker* worker,
|
||||
*/
|
||||
void fast_reload_thread_stop(struct fast_reload_thread* fast_reload_thread);
|
||||
|
||||
/** fast reload thread commands to remote service thread event callback */
|
||||
void fast_reload_service_cb(int fd, short bits, void* arg);
|
||||
|
||||
/** fast reload callback for the remote control client connection */
|
||||
int fast_reload_client_callback(struct comm_point* c, void* arg, int err,
|
||||
struct comm_reply* rep);
|
||||
|
||||
/** fast reload printq delete list */
|
||||
void fast_reload_printq_list_delete(struct fast_reload_printq* list);
|
||||
|
||||
|
||||
+22
-6
@@ -422,12 +422,28 @@ void server_stats_obtain(struct worker* worker, struct worker* who,
|
||||
# endif
|
||||
#endif
|
||||
);
|
||||
log_err("server_stats_obtain: no response from worker %d "
|
||||
"(stats timeout); returning zero stats for this worker",
|
||||
who->thread_num);
|
||||
/* A later reply from the worker, would be sizeof stats reply,
|
||||
* and the worker_handle_control_cmd routine discards if
|
||||
* it is not a 4byte command, when that is received here. */
|
||||
memset(s, 0, sizeof(*s));
|
||||
return;
|
||||
}
|
||||
if(!tube_read_msg(worker->cmd, &reply, &len, 0)) {
|
||||
log_err("server_stats_obtain: failed to read stats from worker "
|
||||
"(tube read error); returning zero stats for this worker");
|
||||
memset(s, 0, sizeof(*s));
|
||||
return;
|
||||
}
|
||||
if(len != (uint32_t)sizeof(*s)) {
|
||||
log_err("server_stats_obtain: wrong stats length %d (expected %d); "
|
||||
"discarding", (int)len, (int)sizeof(*s));
|
||||
free(reply);
|
||||
memset(s, 0, sizeof(*s));
|
||||
return;
|
||||
}
|
||||
if(!tube_read_msg(worker->cmd, &reply, &len, 0))
|
||||
fatal_exit("failed to read stats over cmd channel");
|
||||
if(len != (uint32_t)sizeof(*s))
|
||||
fatal_exit("stats on cmd channel wrong length %d %d",
|
||||
(int)len, (int)sizeof(*s));
|
||||
memcpy(s, reply, (size_t)len);
|
||||
free(reply);
|
||||
}
|
||||
@@ -439,7 +455,7 @@ void server_stats_reply(struct worker* worker, int reset)
|
||||
verbose(VERB_ALGO, "write stats replymsg");
|
||||
if(!tube_write_msg(worker->daemon->workers[0]->cmd,
|
||||
(uint8_t*)&s, sizeof(s), 0))
|
||||
fatal_exit("could not write stat values over cmd channel");
|
||||
log_err("could not write stat values over cmd channel");
|
||||
}
|
||||
|
||||
void server_stats_add(struct ub_stats_info* total, struct ub_stats_info* a)
|
||||
|
||||
+50
-29
@@ -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 */
|
||||
|
||||
@@ -501,7 +500,9 @@ worker_handle_control_cmd(struct tube* ATTR_UNUSED(tube), uint8_t* msg,
|
||||
return;
|
||||
}
|
||||
if(len != sizeof(uint32_t)) {
|
||||
fatal_exit("bad control msg length %d", (int)len);
|
||||
verbose(VERB_ALGO, "bad control msg length %d", (int)len);
|
||||
free(msg);
|
||||
return;
|
||||
}
|
||||
cmd = sldns_read_uint32(msg);
|
||||
free(msg);
|
||||
@@ -714,7 +715,8 @@ apply_respip_action(struct worker* worker, const struct query_info* qinfo,
|
||||
struct respip_client_info* cinfo, struct reply_info* rep,
|
||||
struct sockaddr_storage* addr, socklen_t addrlen,
|
||||
struct ub_packed_rrset_key** alias_rrset,
|
||||
struct reply_info** encode_repp, struct auth_zones* az)
|
||||
struct reply_info** encode_repp, struct auth_zones* az,
|
||||
int* rpz_passthru)
|
||||
{
|
||||
struct respip_action_info actinfo = {0, 0, 0, 0, NULL, 0, NULL};
|
||||
actinfo.action = respip_none;
|
||||
@@ -725,7 +727,7 @@ apply_respip_action(struct worker* worker, const struct query_info* qinfo,
|
||||
return 1;
|
||||
|
||||
if(!respip_rewrite_reply(qinfo, cinfo, rep, encode_repp, &actinfo,
|
||||
alias_rrset, 0, worker->scratchpad, az, NULL,
|
||||
alias_rrset, 0, worker->scratchpad, az, rpz_passthru,
|
||||
worker->env.views, worker->env.respip_set))
|
||||
return 0;
|
||||
|
||||
@@ -772,7 +774,7 @@ answer_from_cache(struct worker* worker, struct query_info* qinfo,
|
||||
int* is_secure_answer, struct ub_packed_rrset_key** alias_rrset,
|
||||
struct reply_info** partial_repp,
|
||||
struct reply_info* rep, uint16_t id, uint16_t flags,
|
||||
struct comm_reply* repinfo, struct edns_data* edns)
|
||||
struct comm_reply* repinfo, struct edns_data* edns, int* rpz_passthru)
|
||||
{
|
||||
time_t timenow = *worker->env.now;
|
||||
uint16_t udpsize = edns->udp_size;
|
||||
@@ -860,7 +862,7 @@ answer_from_cache(struct worker* worker, struct query_info* qinfo,
|
||||
"validation");
|
||||
goto bail_out; /* need to validate cache entry first */
|
||||
} else if(rep->security == sec_status_secure) {
|
||||
if(reply_all_rrsets_secure(rep)) {
|
||||
if(reply_an_ns_rrsets_secure(rep)) {
|
||||
*is_secure_answer = 1;
|
||||
} else {
|
||||
if(must_validate) {
|
||||
@@ -882,7 +884,7 @@ answer_from_cache(struct worker* worker, struct query_info* qinfo,
|
||||
if((worker->daemon->use_response_ip || worker->daemon->use_rpz) &&
|
||||
!partial_rep && !apply_respip_action(worker, qinfo, cinfo, rep,
|
||||
&repinfo->client_addr, repinfo->client_addrlen, alias_rrset,
|
||||
&encode_rep, worker->env.auth_zones)) {
|
||||
&encode_rep, worker->env.auth_zones, rpz_passthru)) {
|
||||
goto bail_out;
|
||||
} else if(partial_rep &&
|
||||
!respip_merge_cname(partial_rep, qinfo, rep, cinfo,
|
||||
@@ -1494,6 +1496,8 @@ worker_handle_request(struct comm_point* c, void* arg, int error,
|
||||
struct reply_info* partial_rep = NULL;
|
||||
struct query_info* lookup_qinfo = &qinfo;
|
||||
struct query_info qinfo_tmp; /* placeholder for lookup_qinfo */
|
||||
uint8_t* alias_orig_qname = NULL; /* original qname for logs, if
|
||||
a local_alias is used to change the qname. */
|
||||
struct respip_client_info* cinfo = NULL, cinfo_tmp;
|
||||
struct timeval wait_time;
|
||||
struct check_request_result check_result = {0,0};
|
||||
@@ -1511,7 +1515,7 @@ worker_handle_request(struct comm_point* c, void* arg, int error,
|
||||
if (worker->stats.max_query_time_us < wait_queue_time)
|
||||
worker->stats.max_query_time_us = wait_queue_time;
|
||||
if(wait_queue_time >
|
||||
(long long)(worker->env.cfg->sock_queue_timeout * 1000000)) {
|
||||
(long long)worker->env.cfg->sock_queue_timeout * 1000000) {
|
||||
/* count and drop queries that were sitting in the socket queue too long */
|
||||
worker->stats.num_queries_timed_out++;
|
||||
return 0;
|
||||
@@ -1550,6 +1554,7 @@ worker_handle_request(struct comm_point* c, void* arg, int error,
|
||||
return 0;
|
||||
}
|
||||
query_error(c->buffer, LDNS_RCODE_FORMERR, 0);
|
||||
sldns_buffer_copy(c->dnscrypt_buffer, c->buffer);
|
||||
return 1;
|
||||
}
|
||||
dname_str(qinfo.qname, buf);
|
||||
@@ -1568,6 +1573,7 @@ worker_handle_request(struct comm_point* c, void* arg, int error,
|
||||
query_error(c->buffer, LDNS_RCODE_SERVFAIL,
|
||||
qinfo.qname_len);
|
||||
worker->stats.num_query_dnscrypt_cleartext++;
|
||||
sldns_buffer_copy(c->dnscrypt_buffer, c->buffer);
|
||||
return 1;
|
||||
}
|
||||
worker->stats.num_query_dnscrypt_cert++;
|
||||
@@ -1699,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);
|
||||
@@ -1828,7 +1836,13 @@ worker_handle_request(struct comm_point* c, void* arg, int error,
|
||||
server_stats_insquery(&worker->stats, c, qinfo.qtype,
|
||||
qinfo.qclass, &edns, repinfo);
|
||||
if(c->type != comm_udp)
|
||||
#ifdef USE_DNSCRYPT
|
||||
edns.udp_size = (c->dnscrypt && repinfo->is_dnscrypted)
|
||||
? sldns_buffer_capacity(c->buffer) - DNSCRYPT_REPLY_HEADER_SIZE
|
||||
: 65535;
|
||||
#else
|
||||
edns.udp_size = 65535; /* max size for TCP replies */
|
||||
#endif
|
||||
if(qinfo.qclass == LDNS_RR_CLASS_CH && answer_chaos(worker, &qinfo,
|
||||
&edns, repinfo, c->buffer)) {
|
||||
regional_free_all(worker->scratchpad);
|
||||
@@ -1928,6 +1942,11 @@ worker_handle_request(struct comm_point* c, void* arg, int error,
|
||||
/* If we've found a local alias, replace the qname with the alias
|
||||
* target before resolving it. */
|
||||
if(qinfo.local_alias) {
|
||||
if(qinfo.local_alias->rrset &&
|
||||
qinfo.local_alias->rrset->rk.dname)
|
||||
/* Store the original qname, used for logs, since
|
||||
* local_alias can be removed by region_free_all. */
|
||||
alias_orig_qname = qinfo.local_alias->rrset->rk.dname;
|
||||
if(!local_alias_shallow_copy_qname(qinfo.local_alias, &qinfo.qname,
|
||||
&qinfo.qname_len)) {
|
||||
regional_free_all(worker->scratchpad);
|
||||
@@ -1975,7 +1994,7 @@ lookup_cache:
|
||||
&alias_rrset, &partial_rep, rep,
|
||||
*(uint16_t*)(void *)sldns_buffer_begin(c->buffer),
|
||||
sldns_buffer_read_u16_at(c->buffer, 2), repinfo,
|
||||
&edns)) {
|
||||
&edns, &rpz_passthru)) {
|
||||
/* prefetch it if the prefetch TTL expired.
|
||||
* Note that if there is more than one pass
|
||||
* its qname must be that used for cache
|
||||
@@ -2093,11 +2112,10 @@ send_reply_rc:
|
||||
{
|
||||
struct timeval tv;
|
||||
memset(&tv, 0, sizeof(tv));
|
||||
if(qinfo.local_alias && qinfo.local_alias->rrset &&
|
||||
qinfo.local_alias->rrset->rk.dname) {
|
||||
if(alias_orig_qname) {
|
||||
/* log original qname, before the local alias was
|
||||
* used to resolve that CNAME to something else */
|
||||
qinfo.qname = qinfo.local_alias->rrset->rk.dname;
|
||||
qinfo.qname = alias_orig_qname;
|
||||
log_reply_info(NO_VERBOSE, &qinfo,
|
||||
&repinfo->client_addr, repinfo->client_addrlen,
|
||||
tv, 1, c->buffer,
|
||||
@@ -2112,7 +2130,7 @@ send_reply_rc:
|
||||
}
|
||||
}
|
||||
#ifdef USE_DNSCRYPT
|
||||
if(!dnsc_handle_uncurved_request(repinfo)) {
|
||||
if(!dnsc_handle_uncurved_request(repinfo, c->buffer)) {
|
||||
return 0;
|
||||
}
|
||||
#endif
|
||||
@@ -2225,23 +2243,16 @@ void worker_probe_timer_cb(void* arg)
|
||||
}
|
||||
|
||||
struct worker*
|
||||
worker_create(struct daemon* daemon, int id, int* ports, int n)
|
||||
worker_create(struct daemon* daemon, int id)
|
||||
{
|
||||
unsigned int seed;
|
||||
struct worker* worker = (struct worker*)calloc(1,
|
||||
sizeof(struct worker));
|
||||
if(!worker)
|
||||
return NULL;
|
||||
worker->numports = n;
|
||||
worker->ports = (int*)memdup(ports, sizeof(int)*n);
|
||||
if(!worker->ports) {
|
||||
free(worker);
|
||||
return NULL;
|
||||
}
|
||||
worker->daemon = daemon;
|
||||
worker->thread_num = id;
|
||||
if(!(worker->cmd = tube_create())) {
|
||||
free(worker->ports);
|
||||
free(worker);
|
||||
return NULL;
|
||||
}
|
||||
@@ -2249,10 +2260,10 @@ worker_create(struct daemon* daemon, int id, int* ports, int n)
|
||||
if(!(worker->rndstate = ub_initstate(daemon->rand))) {
|
||||
log_err("could not init random numbers.");
|
||||
tube_delete(worker->cmd);
|
||||
free(worker->ports);
|
||||
free(worker);
|
||||
return NULL;
|
||||
}
|
||||
rbtree_init(&worker->auth_load_tree, auth_load_tree_cmp);
|
||||
explicit_bzero(&seed, sizeof(seed));
|
||||
return worker;
|
||||
}
|
||||
@@ -2348,14 +2359,14 @@ worker_init(struct worker* worker, struct config_file *cfg,
|
||||
cfg->out_ifs, cfg->num_out_ifs, cfg->do_ip4, cfg->do_ip6,
|
||||
cfg->do_tcp?cfg->outgoing_num_tcp:0, cfg->ip_dscp,
|
||||
worker->daemon->env->infra_cache, worker->rndstate,
|
||||
cfg->use_caps_bits_for_id, worker->ports, worker->numports,
|
||||
cfg->use_caps_bits_for_id,
|
||||
cfg->unwanted_threshold, cfg->outgoing_tcp_mss,
|
||||
&worker_alloc_cleanup, worker,
|
||||
cfg->do_udp || cfg->udp_upstream_without_downstream,
|
||||
worker->daemon->connect_dot_sslctx, cfg->delay_close,
|
||||
cfg->tls_use_sni, dtenv, cfg->udp_connect,
|
||||
cfg->max_reuse_tcp_queries, cfg->tcp_reuse_timeout,
|
||||
cfg->tcp_auth_query_timeout);
|
||||
cfg->tcp_auth_query_timeout, worker->daemon->shared_ports);
|
||||
if(!worker->back) {
|
||||
log_err("could not create outgoing sockets");
|
||||
worker_delete(worker);
|
||||
@@ -2374,6 +2385,8 @@ worker_init(struct worker* worker, struct config_file *cfg,
|
||||
worker_stat_timer_cb, worker);
|
||||
if(!worker->stat_timer) {
|
||||
log_err("could not create statistics timer");
|
||||
worker_delete(worker);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* we use the msg_buffer_size as a good estimate for what the
|
||||
@@ -2506,7 +2519,6 @@ worker_delete(struct worker* worker)
|
||||
tube_delete(worker->cmd);
|
||||
comm_timer_delete(worker->stat_timer);
|
||||
comm_timer_delete(worker->env.probe_timer);
|
||||
free(worker->ports);
|
||||
if(worker->thread_num == 0) {
|
||||
#ifdef UB_ON_WINDOWS
|
||||
wsvc_desetup_worker(worker);
|
||||
@@ -2527,6 +2539,8 @@ worker_delete(struct worker* worker)
|
||||
/* don't touch worker->alloc, as it's maintained in daemon */
|
||||
regional_destroy(worker->env.scratch);
|
||||
regional_destroy(worker->scratchpad);
|
||||
/* The thread id can reference this worker's id value, so clear it. */
|
||||
log_thread_set(NULL);
|
||||
free(worker);
|
||||
}
|
||||
|
||||
@@ -2535,7 +2549,8 @@ worker_send_query(struct query_info* qinfo, uint16_t flags, int dnssec,
|
||||
int want_dnssec, int nocaps, int check_ratelimit,
|
||||
struct sockaddr_storage* addr, socklen_t addrlen, uint8_t* zone,
|
||||
size_t zonelen, int tcp_upstream, int ssl_upstream, char* tls_auth_name,
|
||||
struct module_qstate* q, int* was_ratelimited)
|
||||
struct module_qstate* q, int* was_ratelimited,
|
||||
int* ratelimit_incremented)
|
||||
{
|
||||
struct worker* worker = q->env->worker;
|
||||
struct outbound_entry* e = (struct outbound_entry*)regional_alloc(
|
||||
@@ -2547,7 +2562,7 @@ worker_send_query(struct query_info* qinfo, uint16_t flags, int dnssec,
|
||||
want_dnssec, nocaps, check_ratelimit, tcp_upstream,
|
||||
ssl_upstream, tls_auth_name, addr, addrlen, zone, zonelen, q,
|
||||
worker_handle_service_reply, e, worker->back->udp_buff, q->env,
|
||||
was_ratelimited);
|
||||
was_ratelimited, ratelimit_incremented);
|
||||
if(!e->qsent) {
|
||||
return NULL;
|
||||
}
|
||||
@@ -2596,7 +2611,8 @@ struct outbound_entry* libworker_send_query(
|
||||
struct sockaddr_storage* ATTR_UNUSED(addr), socklen_t ATTR_UNUSED(addrlen),
|
||||
uint8_t* ATTR_UNUSED(zone), size_t ATTR_UNUSED(zonelen), int ATTR_UNUSED(tcp_upstream),
|
||||
int ATTR_UNUSED(ssl_upstream), char* ATTR_UNUSED(tls_auth_name),
|
||||
struct module_qstate* ATTR_UNUSED(q), int* ATTR_UNUSED(was_ratelimited))
|
||||
struct module_qstate* ATTR_UNUSED(q), int* ATTR_UNUSED(was_ratelimited),
|
||||
int* ATTR_UNUSED(ratelimit_incremented))
|
||||
{
|
||||
log_assert(0);
|
||||
return 0;
|
||||
@@ -2638,6 +2654,11 @@ void libworker_event_done_cb(void* ATTR_UNUSED(arg), int ATTR_UNUSED(rcode),
|
||||
log_assert(0);
|
||||
}
|
||||
|
||||
void libworker_alloc_cleanup(void* ATTR_UNUSED(arg))
|
||||
{
|
||||
log_assert(0);
|
||||
}
|
||||
|
||||
int context_query_cmp(const void* ATTR_UNUSED(a), const void* ATTR_UNUSED(b))
|
||||
{
|
||||
log_assert(0);
|
||||
|
||||
+4
-7
@@ -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"
|
||||
@@ -104,10 +105,6 @@ struct worker {
|
||||
struct listen_dnsport* front;
|
||||
/** the backside outside network interface to the auth servers */
|
||||
struct outside_network* back;
|
||||
/** ports to be used by this worker. */
|
||||
int* ports;
|
||||
/** number of ports for this worker */
|
||||
int numports;
|
||||
/** the signal handler */
|
||||
struct comm_signal* comsig;
|
||||
/** commpoint to listen to commands. */
|
||||
@@ -139,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;
|
||||
};
|
||||
|
||||
/**
|
||||
@@ -146,11 +145,9 @@ struct worker {
|
||||
* with backpointers only. Use worker_init on it later.
|
||||
* @param daemon: the daemon that this worker thread is part of.
|
||||
* @param id: the thread number from 0.. numthreads-1.
|
||||
* @param ports: the ports it is allowed to use, array.
|
||||
* @param n: the number of ports.
|
||||
* @return: the new worker or NULL on alloc failure.
|
||||
*/
|
||||
struct worker* worker_create(struct daemon* daemon, int id, int* ports, int n);
|
||||
struct worker* worker_create(struct daemon* daemon, int id);
|
||||
|
||||
/**
|
||||
* Initialize worker.
|
||||
|
||||
+60
-8
@@ -643,6 +643,12 @@ handle_event_moddone(struct module_qstate* qstate, int id)
|
||||
qstate->return_msg->rep &&
|
||||
reply_find_answer_rrset(&qstate->qinfo, qstate->return_msg->rep);
|
||||
int synth_qname = 0;
|
||||
if(could_synth && !has_data && qstate->env->need_to_validate &&
|
||||
qstate->return_msg && qstate->return_msg->rep &&
|
||||
qstate->return_msg->rep->security == sec_status_bogus) {
|
||||
verbose(VERB_ALGO, "dns64: bogus AAAA reply not synthesized");
|
||||
could_synth = 0;
|
||||
}
|
||||
|
||||
if(could_synth &&
|
||||
(!has_data ||
|
||||
@@ -654,8 +660,11 @@ handle_event_moddone(struct module_qstate* qstate, int id)
|
||||
|
||||
/* Store the response in cache. */
|
||||
if( (!iq || !iq->started_no_cache_store) &&
|
||||
!qstate->rpz_applied && !qstate->rpz_passthru &&
|
||||
!qstate->is_subnet_answer &&
|
||||
qstate->return_msg &&
|
||||
qstate->return_msg->rep &&
|
||||
!qstate->fwd_stub_no_cache &&
|
||||
!dns_cache_store(
|
||||
qstate->env, &qstate->qinfo, qstate->return_msg->rep,
|
||||
0, qstate->prefetch_leeway, 0, NULL,
|
||||
@@ -717,8 +726,15 @@ dns64_operate(struct module_qstate* qstate, enum module_ev event, int id,
|
||||
}
|
||||
if(qstate->ext_state[id] == module_finished) {
|
||||
iq = (struct dns64_qstate*)qstate->minfo[id];
|
||||
if(iq && iq->state != DNS64_INTERNAL_QUERY)
|
||||
qstate->no_cache_store = iq->started_no_cache_store;
|
||||
if(iq && iq->state != DNS64_INTERNAL_QUERY) {
|
||||
if(qstate->fwd_stub_no_cache) {
|
||||
/* If the forward/stub has no cache, then
|
||||
* continue with the query with no cache. */
|
||||
qstate->no_cache_store = qstate->fwd_stub_no_cache;
|
||||
} else {
|
||||
qstate->no_cache_store = iq->started_no_cache_store;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -825,6 +841,7 @@ dns64_adjust_a(int id, struct module_qstate* super, struct module_qstate* qstate
|
||||
size_t i, s;
|
||||
struct packed_rrset_data* fd, *dd;
|
||||
struct ub_packed_rrset_key* fk, *dk;
|
||||
int allocated_return_msg = 0;
|
||||
|
||||
verbose(VERB_ALGO, "converting A answers to AAAA answers");
|
||||
|
||||
@@ -840,6 +857,7 @@ dns64_adjust_a(int id, struct module_qstate* super, struct module_qstate* qstate
|
||||
return;
|
||||
memset(super->return_msg, 0, sizeof(*super->return_msg));
|
||||
super->return_msg->qinfo = super->qinfo;
|
||||
allocated_return_msg = 1;
|
||||
}
|
||||
|
||||
rep = qstate->return_msg->rep;
|
||||
@@ -852,11 +870,14 @@ dns64_adjust_a(int id, struct module_qstate* super, struct module_qstate* qstate
|
||||
rep->serve_expired_norec_ttl,
|
||||
rep->an_numrrsets, rep->ns_numrrsets, rep->ar_numrrsets,
|
||||
rep->rrset_count, rep->security, LDNS_EDE_NONE);
|
||||
if(!cp)
|
||||
if(!cp) {
|
||||
if(allocated_return_msg) super->return_msg = NULL;
|
||||
return;
|
||||
}
|
||||
|
||||
/* allocate ub_key structures special or not */
|
||||
if(!reply_info_alloc_rrset_keys(cp, NULL, super->region)) {
|
||||
if(allocated_return_msg) super->return_msg = NULL;
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -871,8 +892,10 @@ dns64_adjust_a(int id, struct module_qstate* super, struct module_qstate* qstate
|
||||
if(i<rep->an_numrrsets && fk->rk.type == htons(LDNS_RR_TYPE_A)) {
|
||||
/* also sets dk->entry.hash */
|
||||
dns64_synth_aaaa_data(fk, fd, dk, &dd, super->region, dns64_env);
|
||||
if(!dd)
|
||||
if(!dd) {
|
||||
if(allocated_return_msg) super->return_msg = NULL;
|
||||
return;
|
||||
}
|
||||
/* Delete negative AAAA record from cache stored by
|
||||
* the iterator module */
|
||||
rrset_cache_remove(super->env->rrset_cache, dk->rk.dname,
|
||||
@@ -889,15 +912,19 @@ dns64_adjust_a(int id, struct module_qstate* super, struct module_qstate* qstate
|
||||
dk->rk.dname = (uint8_t*)regional_alloc_init(super->region,
|
||||
fk->rk.dname, fk->rk.dname_len);
|
||||
|
||||
if(!dk->rk.dname)
|
||||
if(!dk->rk.dname) {
|
||||
if(allocated_return_msg) super->return_msg = NULL;
|
||||
return;
|
||||
}
|
||||
|
||||
s = packed_rrset_sizeof(fd);
|
||||
dd = (struct packed_rrset_data*)regional_alloc_init(
|
||||
super->region, fd, s);
|
||||
|
||||
if(!dd)
|
||||
if(!dd) {
|
||||
if(allocated_return_msg) super->return_msg = NULL;
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
packed_rrset_ptr_fixup(dd);
|
||||
@@ -928,8 +955,10 @@ dns64_adjust_ptr(struct module_qstate* qstate, struct module_qstate* super)
|
||||
return;
|
||||
super->return_msg->qinfo = super->qinfo;
|
||||
if (!(super->return_msg->rep = reply_info_copy(qstate->return_msg->rep,
|
||||
NULL, super->region)))
|
||||
NULL, super->region))) {
|
||||
super->return_msg = NULL;
|
||||
return;
|
||||
}
|
||||
|
||||
/*
|
||||
* Adjust the domain name of the answer RR set so that it matches the
|
||||
@@ -939,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);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -998,6 +1028,21 @@ dns64_inform_super(struct module_qstate* qstate, int id,
|
||||
/* Use return code from A query in response to client. */
|
||||
if (super->return_rcode != LDNS_RCODE_NOERROR)
|
||||
super->return_rcode = qstate->return_rcode;
|
||||
/* RPZ applied to the subquery need to then change (not cache)
|
||||
* the super query. With the super query not cached, it is
|
||||
* going to run the state machine modules on incoming queries,
|
||||
* that fetch the subquery (cache) response, and modify it
|
||||
* according to the rpz policy. That makes the synthesized
|
||||
* super query also adjusted by rpz policies. But loses cache
|
||||
* hits. Even though the subquery likely is answered from cache,
|
||||
* internally in its state machine process. */
|
||||
if(qstate->rpz_applied)
|
||||
super->rpz_applied = 1;
|
||||
if(qstate->rpz_passthru)
|
||||
super->rpz_passthru = 1;
|
||||
|
||||
/* Since the super qstate has a new response, its errinf is removed. */
|
||||
super->errinf = NULL;
|
||||
|
||||
/* Generate a response suitable for the original query. */
|
||||
if (qstate->qinfo.qtype == LDNS_RR_TYPE_A) {
|
||||
@@ -1006,9 +1051,16 @@ dns64_inform_super(struct module_qstate* qstate, int id,
|
||||
log_assert(qstate->qinfo.qtype == LDNS_RR_TYPE_PTR);
|
||||
dns64_adjust_ptr(qstate, super);
|
||||
}
|
||||
/* If the sub-query has no cache store, then also the super query. */
|
||||
if(qstate->fwd_stub_no_cache)
|
||||
super->fwd_stub_no_cache = 1;
|
||||
|
||||
/* Store the generated response in cache. */
|
||||
if ( (!super_dq || !super_dq->started_no_cache_store) &&
|
||||
if ( super->return_msg && super->return_msg->rep &&
|
||||
(!super_dq || !super_dq->started_no_cache_store) &&
|
||||
!qstate->fwd_stub_no_cache &&
|
||||
!super->rpz_applied && !super->rpz_passthru &&
|
||||
!super->is_subnet_answer &&
|
||||
!dns_cache_store(super->env, &super->qinfo, super->return_msg->rep,
|
||||
0, super->prefetch_leeway, 0, NULL, super->query_flags,
|
||||
qstate->qstarttime, qstate->is_valrec))
|
||||
|
||||
+31
-4
@@ -474,10 +474,18 @@ dnscrypt_server_curve(const dnsccert *cert,
|
||||
uint8_t *const buf = sldns_buffer_begin(buffer);
|
||||
size_t len = sldns_buffer_limit(buffer);
|
||||
|
||||
if(len + DNSCRYPT_REPLY_HEADER_SIZE > sldns_buffer_capacity(buffer))
|
||||
return -1;
|
||||
sldns_buffer_clear(buffer);
|
||||
|
||||
if(udp){
|
||||
if (max_len > max_reply_size)
|
||||
max_len = max_reply_size;
|
||||
}
|
||||
if(max_len > sldns_buffer_capacity(buffer))
|
||||
max_len = sldns_buffer_capacity(buffer);
|
||||
if(max_len > 65535)
|
||||
max_len = 65535;
|
||||
|
||||
|
||||
memcpy(nonce, client_nonce, crypto_box_HALF_NONCEBYTES);
|
||||
@@ -520,6 +528,7 @@ dnscrypt_server_curve(const dnsccert *cert,
|
||||
DNSCRYPT_MAGIC_HEADER_LEN,
|
||||
nonce,
|
||||
crypto_box_NONCEBYTES);
|
||||
sldns_buffer_flip(buffer);
|
||||
sldns_buffer_set_limit(buffer, len + DNSCRYPT_REPLY_HEADER_SIZE);
|
||||
return 0;
|
||||
}
|
||||
@@ -663,6 +672,8 @@ dnsc_find_cert(struct dnsc_env* dnscenv, struct sldns_buffer* buffer)
|
||||
}
|
||||
dnscrypt_header = (struct dnscrypt_query_header *)sldns_buffer_begin(buffer);
|
||||
for (i = 0U; i < dnscenv->signed_certs_count; i++) {
|
||||
if(!certs[i].keypair)
|
||||
continue;
|
||||
if (memcmp(certs[i].magic_query, dnscrypt_header->magic_query,
|
||||
DNSCRYPT_MAGIC_HEADER_LEN) == 0) {
|
||||
return &certs[i];
|
||||
@@ -804,6 +815,7 @@ dnsc_parse_keys(struct dnsc_env *env, struct config_file *cfg)
|
||||
sizeof *env->keypairs);
|
||||
env->certs = sodium_allocarray(env->signed_certs_count,
|
||||
sizeof *env->certs);
|
||||
memset(env->certs, 0, env->signed_certs_count * sizeof(*env->certs));
|
||||
|
||||
cert_id = 0U;
|
||||
keypair_id = 0U;
|
||||
@@ -830,7 +842,14 @@ dnsc_parse_keys(struct dnsc_env *env, struct config_file *cfg)
|
||||
if(memcmp(current_keypair->crypt_publickey,
|
||||
env->signed_certs[c].server_publickey,
|
||||
crypto_box_PUBLICKEYBYTES) == 0) {
|
||||
dnsccert *current_cert = &env->certs[cert_id++];
|
||||
dnsccert* current_cert;
|
||||
if(cert_id >= env->signed_certs_count) {
|
||||
log_err("dnscrypt: secret key %s matches a cert that "
|
||||
"is already bound to another key (duplicate "
|
||||
"dnscrypt-secret-key?)", head->str);
|
||||
return -1;
|
||||
}
|
||||
current_cert = &env->certs[cert_id++];
|
||||
found_cert = 1;
|
||||
current_cert->keypair = current_keypair;
|
||||
memcpy(current_cert->magic_query,
|
||||
@@ -912,12 +931,13 @@ dnsc_handle_curved_request(struct dnsc_env* dnscenv,
|
||||
}
|
||||
|
||||
int
|
||||
dnsc_handle_uncurved_request(struct comm_reply *repinfo)
|
||||
dnsc_handle_uncurved_request(struct comm_reply *repinfo,
|
||||
struct sldns_buffer* buffer)
|
||||
{
|
||||
if(!repinfo->c->dnscrypt) {
|
||||
return 1;
|
||||
}
|
||||
sldns_buffer_copy(repinfo->c->dnscrypt_buffer, repinfo->c->buffer);
|
||||
sldns_buffer_copy(repinfo->c->dnscrypt_buffer, buffer);
|
||||
if(!repinfo->is_dnscrypted) {
|
||||
return 1;
|
||||
}
|
||||
@@ -963,12 +983,19 @@ dnsc_create(void)
|
||||
int
|
||||
dnsc_apply_cfg(struct dnsc_env *env, struct config_file *cfg)
|
||||
{
|
||||
int nkeys;
|
||||
if(dnsc_parse_certs(env, cfg) <= 0) {
|
||||
fatal_exit("dnsc_apply_cfg: no cert file loaded");
|
||||
}
|
||||
if(dnsc_parse_keys(env, cfg) <= 0) {
|
||||
nkeys = dnsc_parse_keys(env, cfg);
|
||||
if(nkeys <= 0) {
|
||||
fatal_exit("dnsc_apply_cfg: no key file loaded");
|
||||
}
|
||||
if((size_t)nkeys < env->signed_certs_count) {
|
||||
fatal_exit("dnsc_apply_cfg: %u dnscrypt-provider-cert file(s) have no "
|
||||
"matching dnscrypt-secret-key",
|
||||
(unsigned)(env->signed_certs_count - (size_t)nkeys));
|
||||
}
|
||||
randombytes_buf(env->hash_key, sizeof env->hash_key);
|
||||
env->provider_name = cfg->dnscrypt_provider;
|
||||
|
||||
|
||||
+2
-1
@@ -128,7 +128,8 @@ int dnsc_handle_curved_request(struct dnsc_env* dnscenv,
|
||||
* \return 0 in case of failure.
|
||||
*/
|
||||
|
||||
int dnsc_handle_uncurved_request(struct comm_reply *repinfo);
|
||||
int dnsc_handle_uncurved_request(struct comm_reply *repinfo,
|
||||
struct sldns_buffer* buffer);
|
||||
|
||||
/**
|
||||
* Computes the size of the shared secret cache entry.
|
||||
|
||||
+36
-17
@@ -176,26 +176,29 @@ dt_create(struct config_file* cfg)
|
||||
env->dtio = dt_io_thread_create();
|
||||
if(!env->dtio) {
|
||||
log_err("malloc failure");
|
||||
free(env);
|
||||
dt_delete(env);
|
||||
return NULL;
|
||||
}
|
||||
if(!dt_io_thread_apply_cfg(env->dtio, cfg)) {
|
||||
dt_io_thread_delete(env->dtio);
|
||||
free(env);
|
||||
dt_delete(env);
|
||||
return NULL;
|
||||
}
|
||||
if(!dt_apply_cfg(env, cfg)) {
|
||||
dt_delete(env);
|
||||
return NULL;
|
||||
}
|
||||
dt_apply_cfg(env, cfg);
|
||||
return env;
|
||||
}
|
||||
|
||||
static void
|
||||
static int
|
||||
dt_apply_identity(struct dt_env *env, struct config_file *cfg)
|
||||
{
|
||||
char buf[MAXHOSTNAMELEN+1];
|
||||
if (!cfg->dnstap_send_identity) {
|
||||
free(env->identity);
|
||||
env->identity = NULL;
|
||||
return;
|
||||
env->len_identity = 0;
|
||||
return 1;
|
||||
}
|
||||
free(env->identity);
|
||||
if (cfg->dnstap_identity == NULL || cfg->dnstap_identity[0] == 0) {
|
||||
@@ -203,36 +206,49 @@ dt_apply_identity(struct dt_env *env, struct config_file *cfg)
|
||||
buf[MAXHOSTNAMELEN] = 0;
|
||||
env->identity = strdup(buf);
|
||||
} else {
|
||||
fatal_exit("dt_apply_identity: gethostname() failed");
|
||||
log_err("dt_apply_identity: gethostname() failed: %s",
|
||||
strerror(errno));
|
||||
env->identity = NULL;
|
||||
env->len_identity = 0;
|
||||
return 0;
|
||||
}
|
||||
} else {
|
||||
env->identity = strdup(cfg->dnstap_identity);
|
||||
}
|
||||
if (env->identity == NULL)
|
||||
fatal_exit("dt_apply_identity: strdup() failed");
|
||||
if (env->identity == NULL) {
|
||||
log_err("dt_apply_identity: strdup() failed");
|
||||
env->len_identity = 0;
|
||||
return 0;
|
||||
}
|
||||
env->len_identity = (unsigned int)strlen(env->identity);
|
||||
verbose(VERB_OPS, "dnstap identity field set to \"%s\"",
|
||||
env->identity);
|
||||
return 1;
|
||||
}
|
||||
|
||||
static void
|
||||
static int
|
||||
dt_apply_version(struct dt_env *env, struct config_file *cfg)
|
||||
{
|
||||
if (!cfg->dnstap_send_version) {
|
||||
free(env->version);
|
||||
env->version = NULL;
|
||||
return;
|
||||
env->len_version = 0;
|
||||
return 1;
|
||||
}
|
||||
free(env->version);
|
||||
if (cfg->dnstap_version == NULL || cfg->dnstap_version[0] == 0)
|
||||
env->version = strdup(PACKAGE_STRING);
|
||||
else
|
||||
env->version = strdup(cfg->dnstap_version);
|
||||
if (env->version == NULL)
|
||||
fatal_exit("dt_apply_version: strdup() failed");
|
||||
if (env->version == NULL) {
|
||||
log_err("dt_apply_version: strdup() failed");
|
||||
env->len_version = 0;
|
||||
return 0;
|
||||
}
|
||||
env->len_version = (unsigned int)strlen(env->version);
|
||||
verbose(VERB_OPS, "dnstap version field set to \"%s\"",
|
||||
env->version);
|
||||
return 1;
|
||||
}
|
||||
|
||||
void
|
||||
@@ -276,15 +292,18 @@ dt_apply_logcfg(struct dt_env *env, struct config_file *cfg)
|
||||
lock_basic_unlock(&env->sample_lock);
|
||||
}
|
||||
|
||||
void
|
||||
int
|
||||
dt_apply_cfg(struct dt_env *env, struct config_file *cfg)
|
||||
{
|
||||
if (!cfg->dnstap)
|
||||
return;
|
||||
return 1;
|
||||
|
||||
dt_apply_identity(env, cfg);
|
||||
dt_apply_version(env, cfg);
|
||||
dt_apply_logcfg(env, cfg);
|
||||
if(!dt_apply_identity(env, cfg))
|
||||
return 0;
|
||||
if(!dt_apply_version(env, cfg))
|
||||
return 0;
|
||||
return 1;
|
||||
}
|
||||
|
||||
int
|
||||
|
||||
+2
-2
@@ -102,9 +102,9 @@ dt_create(struct config_file* cfg);
|
||||
* Apply config settings.
|
||||
* @param env: dnstap environment object.
|
||||
* @param cfg: new config settings.
|
||||
* @return false on failure.
|
||||
*/
|
||||
void
|
||||
dt_apply_cfg(struct dt_env *env, struct config_file *cfg);
|
||||
int dt_apply_cfg(struct dt_env *env, struct config_file *cfg);
|
||||
|
||||
/**
|
||||
* Apply config settings for log enable for message types.
|
||||
|
||||
+1
-1
@@ -2144,7 +2144,7 @@ static void* dnstap_io(void* arg)
|
||||
#endif
|
||||
log_thread_set(&dtio->threadnum);
|
||||
|
||||
ub_thread_setname(dtio->tid, name);
|
||||
ub_thread_setname(ub_thread_self(), name);
|
||||
|
||||
/* setup */
|
||||
verbose(VERB_ALGO, "start dnstap io thread");
|
||||
|
||||
@@ -1659,7 +1659,8 @@ struct outbound_entry* worker_send_query(
|
||||
socklen_t ATTR_UNUSED(addrlen), uint8_t* ATTR_UNUSED(zone),
|
||||
size_t ATTR_UNUSED(zonelen), int ATTR_UNUSED(tcp_upstream),
|
||||
int ATTR_UNUSED(ssl_upstream), char* ATTR_UNUSED(tls_auth_name),
|
||||
struct module_qstate* ATTR_UNUSED(q), int* ATTR_UNUSED(was_ratelimited))
|
||||
struct module_qstate* ATTR_UNUSED(q), int* ATTR_UNUSED(was_ratelimited),
|
||||
int* ATTR_UNUSED(ratelimit_incremented))
|
||||
{
|
||||
log_assert(0);
|
||||
return 0;
|
||||
@@ -1693,7 +1694,8 @@ struct outbound_entry* libworker_send_query(
|
||||
socklen_t ATTR_UNUSED(addrlen), uint8_t* ATTR_UNUSED(zone),
|
||||
size_t ATTR_UNUSED(zonelen), int ATTR_UNUSED(tcp_upstream),
|
||||
int ATTR_UNUSED(ssl_upstream), char* ATTR_UNUSED(tls_auth_name),
|
||||
struct module_qstate* ATTR_UNUSED(q), int* ATTR_UNUSED(was_ratelimited))
|
||||
struct module_qstate* ATTR_UNUSED(q), int* ATTR_UNUSED(was_ratelimited),
|
||||
int* ATTR_UNUSED(ratelimit_incremented))
|
||||
{
|
||||
log_assert(0);
|
||||
return 0;
|
||||
@@ -1735,6 +1737,11 @@ void libworker_event_done_cb(void* ATTR_UNUSED(arg), int ATTR_UNUSED(rcode),
|
||||
log_assert(0);
|
||||
}
|
||||
|
||||
void libworker_alloc_cleanup(void* ATTR_UNUSED(arg))
|
||||
{
|
||||
log_assert(0);
|
||||
}
|
||||
|
||||
int context_query_cmp(const void* ATTR_UNUSED(a), const void* ATTR_UNUSED(b))
|
||||
{
|
||||
log_assert(0);
|
||||
|
||||
+763
@@ -1,3 +1,693 @@
|
||||
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.
|
||||
- Unit test for block_a and block_aaaa.
|
||||
- Fix #1477: respip + dns64: dns64 uses A records modified by
|
||||
respip instead of original A records. Adds local-zone types
|
||||
block_a_wdata and block_aaaa_wdata, that are like block_a
|
||||
and block_aaaa, and uses local-data if present.
|
||||
- set code repository version to 1.26.0.
|
||||
- Update generated man pages.
|
||||
- Fix to allow test fake sha1 on systems with possible sha1
|
||||
support.
|
||||
- Fix to use sha256 for unbound-anchor unit test.
|
||||
- Fix unbound-anchor check for return value of
|
||||
X509_NAME_get_text_by_NID of the emailaddress.
|
||||
- Fix lock test protect for auth zone change.
|
||||
- Fix to lock shared_ports structure during initialisation.
|
||||
- Fix to lock anchor structure when file is set for it in
|
||||
parse of the header.
|
||||
- Merge #1480 from petrvaganoff: authzone: fix memory leak in
|
||||
xfer_set_masters() error path.
|
||||
- Fix unused variable warnings in shared_ports_fetch_random
|
||||
and shared_ports_return_port when compiled without threads.
|
||||
- Fix to guard access to shared ports interface array during
|
||||
set up, for analyzer.
|
||||
- Fix sign of comparison warning in shared ports setup.
|
||||
- Fix #1481: Fix to use tls-port after referral if
|
||||
tls-upstream is set.
|
||||
- Merge #1479 from psumbera: Fix pthread detection on
|
||||
Solaris 11.4.
|
||||
- Fix to call OPENSSL_cleanup on exit when that is defined.
|
||||
|
||||
23 July 2026: Wouter
|
||||
- Updated credits for Xuanchao Xie in 22 july changelog.
|
||||
- Merge #1478 from petrvaganoff: pythonmod: add check return
|
||||
value after ftell().
|
||||
- Fix that for NSEC3 proofs the NSEC3 zone, as the b32.name is
|
||||
checked to be the same as the signer name. Also RRSIGs are
|
||||
not considered valid when an NSEC3 is not b32.signerzone.
|
||||
Thanks to Qifan Zhang, Palo Alto Networks, for the report.
|
||||
- Fix that the aggressive negative cache does not insert NSEC
|
||||
records with overreaching next owner name. Also the result
|
||||
is not above the trust anchor's bailiwick. Also RRSIGS are
|
||||
not considered valid when an NSEC next owner name is not
|
||||
under the signer zone name. Thanks to Qifan Zhang, Palo
|
||||
Alto Networks, for the report.
|
||||
- Fix mesh cycle detection for configuration with respip CNAME
|
||||
loop and tagged clients. Thanks to Qifan Zhang, Palo Alto
|
||||
Networks, for the report.
|
||||
|
||||
22 July 2026: Wouter
|
||||
- Release tag for 1.25.2, with the security commits:
|
||||
- Fix CVE-2026-14586, Assertion in libngtcp2 when under pressure
|
||||
in high concurrency DNS-over-QUIC environments. Thanks to Kunta
|
||||
Chu, Kaihua Wang, and Jianjun Chen from Tsinghua University,
|
||||
for the report.
|
||||
- Fix CVE-2026-32665, Remote DNS-over-QUIC denial of
|
||||
service due to `quic-size` budget bypass. Thanks to N0zoM1z0
|
||||
(https://github.com/N0zoM1z0) for the report. In addition, thanks to
|
||||
Kunta Chu, Kaihua Wang, and Jianjun Chen from Tsinghua University,
|
||||
for also reporting this issue. In addition, thanks to Qifan Zhang,
|
||||
Palo Alto Networks, for also reporting this issue. In addition,
|
||||
thanks to Xuanchao Xie, Lutong Chen, and Kaiping Xue of the
|
||||
University of Science and Technology of China (USTC), for also
|
||||
reporting this issue.
|
||||
- Fix CVE-2026-40691, Packet of death for DNSCrypt over TCP. Thanks
|
||||
to Qifan Zhang, Palo Alto Networks, for the report. In addition,
|
||||
thanks to Trung Nguyen (@everping) of CyStack, for also reporting
|
||||
this issue.
|
||||
- Fix CVE-2026-41637, Degradation of resolution service from
|
||||
improperly accounted client-terminated DNS-over-QUIC queries. Thanks
|
||||
to Qifan Zhang, Palo Alto Networks, for the report.
|
||||
- Fix CVE-2026-42955, Extra fix for CVE-2026-40622 to also clamp
|
||||
the TTL of A/AAAA records disallowing a one-time 'ghost domain'
|
||||
delegation renewal via glue records. Thanks to Qifan Zhang, Palo
|
||||
Alto Networks, for the report.
|
||||
- Fix CVE-2026-44621, Libunbound applications configured with
|
||||
'unwanted-reply-threshold' could eventually be abruptly
|
||||
terminated. Thanks to Qifan Zhang, Palo Alto Networks, for the
|
||||
report.
|
||||
- Fix CVE-2026-44687, Off-by-one error in 'harden-below-nxdomain'
|
||||
logic can shadow a stub/forward zone by a legitimate parent's
|
||||
NXDOMAIN. Thanks to Qifan Zhang, Palo Alto Networks, for the report.
|
||||
- Fix CVE-2026-44690, Cross-zone wildcard cache poisoning via
|
||||
RRSIG.labels manipulation. Thanks to Qifan Zhang, Palo Alto
|
||||
Networks, for the report.
|
||||
- Fix CVE-2026-46582, A wildcard replay, as another piece of data,
|
||||
triggers poisoning in the serve expired reply path. Thanks to
|
||||
Qifan Zhang, Palo Alto Networks, for the report.
|
||||
- Fix CVE-2026-50045, 'max-global-quota' reset by DNSSEC validation
|
||||
restarts. Thanks to Kunjie Shang, University of Science and
|
||||
Technology of China, for the report.
|
||||
- Fix CVE-2026-50046, Possible heap use-after-free in an error path
|
||||
when a DoT forwarded query is jostled out. Thanks to Qifan Zhang,
|
||||
Palo Alto Networks, for the report.
|
||||
- Fix CVE-2026-50243, 'response-ip'/'rpz' can rewrite BOGUS answers
|
||||
instead of returning SERVFAIL. Thanks to Qifan Zhang, Palo Alto
|
||||
Networks, for the report.
|
||||
- Fix CVE-2026-50248, BOGUS configured primary hostname accepted for
|
||||
XFR in auth/rpz zones. Thanks to Qifan Zhang, Palo Alto Networks,
|
||||
for the report.
|
||||
- Fix CVE-2026-50251, Attacker supplied `0.0.0.0`/`::` glue triggers
|
||||
defensive full-cache flush. Thanks to Qifan Zhang, Palo Alto
|
||||
Networks, for the report.
|
||||
- Fix CVE-2026-50252, Possible cache poisoning attack by mapping
|
||||
source port population per thread. Thanks to Inbal Schussheim and
|
||||
Amit Klein, Hebrew University, for the report.
|
||||
- Fix CVE-2026-52863, Memory corruption could lead to crash and
|
||||
denial of service. Thanks to Qifan Zhang, Palo Alto Networks,
|
||||
for the report.
|
||||
- Fix CVE-2026-54478, DNS Cookie bypass when combined with
|
||||
proxy-protocol use. Thanks to Qifan Zhang, Palo Alto Networks,
|
||||
for the report.
|
||||
- Fix CVE-2026-55708, Privacy/configuration issue when adding local
|
||||
data in views through 'unbound-control'. Thanks to Qifan Zhang,
|
||||
Palo Alto Networks, for the report.
|
||||
- Fix CVE-2026-55717, 'serve-expired-client-timeout' and 'response-ip'
|
||||
CNAME redirect could lead to a crash. Thanks to Qifan Zhang, Palo
|
||||
Alto Networks, for the report. In addition, thanks to Xin Wang,
|
||||
Jiapeng Li, and Jiajia Liu, Northwestern Polytechnical University,
|
||||
for also reporting this issue.
|
||||
- Fix CVE-2026-55973, 'dns-error-reporting: yes' leads to stack buffer
|
||||
overflow. Thanks to Qifan Zhang, Palo Alto Networks, for the report.
|
||||
- Fix CVE-2026-55990, Packet of death for a DNSCrypt misconfigured
|
||||
Unbound. Thanks to Qifan Zhang, Palo Alto Networks, for the report.
|
||||
- Fix CVE-2026-55991, Remote DNS-over-QUIC (DoQ) flow-control
|
||||
assertion failure in libngtcp2. Thanks to Qifan Zhang, Palo Alto
|
||||
Networks, for the report. In addition, thanks to Xuanchao Xie,
|
||||
Lutong Chen, and Kaiping Xue of the University of Science and
|
||||
Technology of China (USTC), for also reporting this issue.
|
||||
- Fix CVE-2026-56416, Possible heap buffer overflow when validator
|
||||
canonicalizes RDATA that contains domain name. Thanks to Qifan
|
||||
Zhang, Palo Alto Networks, for the report.
|
||||
- Fix CVE-2026-56444, Degradation of resolution service when
|
||||
'discard-timeout' and 'serve-expired-client-timeout' are combined in
|
||||
unusual configuration. Thanks to Qifan Zhang, Palo Alto Networks,
|
||||
for the report. In addition, thanks to Xin Wang, Jiapeng Li,
|
||||
and Jiajia Liu, Northwestern Polytechnical University, for also
|
||||
reporting this issue. In addition, thanks to Haruki Oyama (Waseda
|
||||
University), for also reporting this issue.
|
||||
- Set the repository to 1.25.3, it continues with the previous
|
||||
changes.
|
||||
- Unit test for CVE-2026-42955.
|
||||
- Unit test for CVE-2026-44687.
|
||||
- Unit test for CVE-2026-44690.
|
||||
- Unit test for CVE-2026-46582.
|
||||
- Unit test for CVE-2026-50045.
|
||||
- Unit test for CVE-2026-50243.
|
||||
- Unit test for CVE-2026-50248.
|
||||
- Unit test for CVE-2026-55717.
|
||||
- Unit test for CVE-2026-55973.
|
||||
- Unit test for CVE-2026-56416.
|
||||
- Fix error in log printout in fix for CVE-2026-50248, when the
|
||||
primary name is bogus.
|
||||
- iana portlist update.
|
||||
|
||||
21 July 2026: Wouter
|
||||
- Merge #1476 from petrvaganoff: ipsecmod: fix possible deref
|
||||
on null after reply_find_answer_rrset().
|
||||
|
||||
20 July 2026: Wouter
|
||||
- Merge #1475 from petrvaganoff: ipsecmod: fix deref on null
|
||||
in ipsecmod-whitelist after OOM.
|
||||
- Fix #1474: DoQ responses are never padded - pad-responses
|
||||
does not apply to comm_doq (RFC 9250 §5.4 MUST).
|
||||
|
||||
9 July 2026: Wouter
|
||||
- Merge #1383 from jdek: Fix randomness generation on
|
||||
macOS/iOS under chroot.
|
||||
- Fix unit test for malformed svcb for test on Windows.
|
||||
|
||||
2 July 2026: Wouter
|
||||
- Merge #1087: Overload `local_data_remove` to support removing
|
||||
specific records.
|
||||
|
||||
30 June 2026: Wouter
|
||||
- Fix #1469: dohclient: DoH POST missing content-length → :status
|
||||
400 from strict resolvers (Cloudflare, Mullvad).
|
||||
- iana portlist updated.
|
||||
|
||||
26 June 2026: Wouter
|
||||
- Merge #1467: daemon: fix DEREF_AFTER_NULL.EX.COND on
|
||||
worker_init. This fixes error handling if the worker
|
||||
stat_timer allocation has an out of memory error. That
|
||||
makes the server not crash later, attempting to use it.
|
||||
|
||||
24 June 2026: Wouter
|
||||
- Merge #1465 from dag-erling: Add libunbound/remote.h. Add
|
||||
a shared header containing prototypes for functions that
|
||||
both ends of a remote control connection need to implement.
|
||||
|
||||
19 June 2026: Wouter
|
||||
- Fix for #1457: fix thread setname for thread start of
|
||||
dnstap, and fast_reload.
|
||||
- Fix to update github ci actions/checkout to v7.
|
||||
- Fix warning about file_string_matches in unbound-checkconf.
|
||||
|
||||
17 June 2026: Wouter
|
||||
- Fix that after fast_reload the disown of the auth zone
|
||||
transfer task cleans the chunk list. Also fix the
|
||||
auth_transfer_limit test to use a forwarder for each type
|
||||
of failure, so the one is not blocked by the other waiting.
|
||||
- Fix to remove debug from auth_transfer_limit test.
|
||||
- Fix that unbound-checkconf checks if an auth-zone download
|
||||
can overwrite another file, by filename collision.
|
||||
Thanks to Qifan Zhang, Palo Alto Networks, for the report.
|
||||
- Fix that malloc failure in auth-zone insert rr does
|
||||
not create an empty node and does not cause an infinite
|
||||
loop. Thanks to Qifan Zhang, Palo Alto Networks, for
|
||||
the report.
|
||||
- Fix that unbound-control auth_zone_reload stops the
|
||||
server answering from the zone after a failure to read.
|
||||
Thanks to Qifan Zhang, Palo Alto Networks, for the report.
|
||||
- Fix that malloc failure in dns64_inform_super does
|
||||
not set up a half-built reply for cache store, that could
|
||||
lead to a crash. Thanks to Qifan Zhang, Palo Alto Networks,
|
||||
for the report.
|
||||
- Fix that malloc failure for new_local_rrset for RPZ qname
|
||||
trigger RR insert does not crash. It does not link a
|
||||
partial RRset, and logs an error on failure, and cleans
|
||||
up the dname allocation. Thanks to Qifan Zhang, Palo Alto
|
||||
Networks, for the report.
|
||||
- Fix that malloc failure in doq connection setup, does
|
||||
not crash in doq connection delete later. Thanks to Qifan
|
||||
Zhang, Palo Alto Networks, for the report.
|
||||
- Fix that malloc failure for ngtcp2_conn_server_new
|
||||
cleans up reference that older ngtcp2 versions can leave.
|
||||
Thanks to Qifan Zhang, Palo Alto Networks, for the report.
|
||||
- Fix that on malloc failure during accept of TCP, the
|
||||
socket is not left to cause a read event loop. It uses
|
||||
slow-accept to delay accepting new connections, if
|
||||
that fails it drops the new connections. When the tcp
|
||||
connection usage is full, it waits for 50msec, to allow
|
||||
existing queries to be resolved. Thanks to Qifan Zhang,
|
||||
Palo Alto Networks, for the report.
|
||||
- Fix that malloc failure for rpz_strip_nsdname is
|
||||
checked and handled, so that it does not crash later.
|
||||
Thanks to Qifan Zhang, Palo Alto Networks, for the report.
|
||||
- Fix that malloc failure during edns subnet addrtree
|
||||
insert is checked, so it does not crash later. Thanks to
|
||||
Qifan Zhang, Palo Alto Networks, for the report.
|
||||
- Fix to check the return value of auth_xfer_create
|
||||
during fast_reload auth-zone add and change processing.
|
||||
Thanks to Qifan Zhang, Palo Alto Networks, for the report.
|
||||
- Fix to check for malloc failure in rpz response create,
|
||||
for nodata and nxdomain, so it does not crash later.
|
||||
Thanks to Qifan Zhang, Palo Alto Networks, for the report.
|
||||
- Fix that fast_reload does not terminate the server
|
||||
on malloc failure for dnstap, or if gethostname fails.
|
||||
Thanks to Qifan Zhang, Palo Alto Networks, for the report.
|
||||
- Fix after malloc failure for stats, then it drains the pipe
|
||||
so the internal messaging stays correct. Also it does
|
||||
not exit the server if stats pipe communication fails.
|
||||
Thanks to Qifan Zhang, Palo Alto Networks, for the report.
|
||||
- Fix that fast_reload does not terminate the server
|
||||
on config read failure after malloc failure. Thanks to
|
||||
Qifan Zhang, Palo Alto Networks, for the report.
|
||||
- Fix that fast_reload does not terminate the server if
|
||||
random init for DNS cookies fails. The data is only random
|
||||
generated if cookies are enabled, and the random data
|
||||
is necessary. Thanks to Qifan Zhang, Palo Alto Networks,
|
||||
for the report.
|
||||
|
||||
17 June 2026: Yorgos
|
||||
- Fix memory leak on DNAME 0TTL records.
|
||||
|
||||
16 June 2026: Wouter
|
||||
- Fix to disallow $INCLUDE for secondary zones. Start up
|
||||
of server continues if a secondary zone fails to load.
|
||||
Failed loads clear the zone data, so there is no partial
|
||||
zone. Thanks to Qifan Zhang, Palo Alto Networks, for
|
||||
the report.
|
||||
- Fix that when SVCB records cannot be written out, and
|
||||
are written in unknown format, that the zone read allows
|
||||
such unknown format SVCB records. Thanks to Qifan Zhang,
|
||||
Palo Alto Networks, for the report.
|
||||
- Fix that a half-written trust anchor file does not crash
|
||||
the server at runtime. It unlinks a wrong file from the list.
|
||||
Thanks to Qifan Zhang, Palo Alto Networks, for the report.
|
||||
- Fix that auth-zone, and RPZ zones, do not allow out-of-zone
|
||||
records. These are records that are not under the zone apex.
|
||||
The out-of-zone records are dropped from the zone contents.
|
||||
Thanks to Qifan Zhang, Palo Alto Networks, for the report.
|
||||
- Fix that dns64 does not ignore the `forward-no-cache` and
|
||||
`stub-no-cache` options. Thanks to Qifan Zhang, Palo Alto
|
||||
Networks, for the report.
|
||||
- Fix that a signed wildcard NSEC, is checked before use,
|
||||
so it does not allow insecure DS proofs inappropriately.
|
||||
Thanks to Qifan Zhang, Palo Alto Networks, for the report.
|
||||
- Fix that after malloc failure a half-built local_alias does
|
||||
not crash the server. Thanks to Qifan Zhang, Palo Alto
|
||||
Networks, for the report.
|
||||
- Fix that for a zonefile only zone, if that file does not
|
||||
exist on server start, the server continues to start with
|
||||
a warning log message. Thanks to Qifan Zhang, Palo Alto
|
||||
Networks, for the report.
|
||||
- Fix that after malloc failure in RPZ load a half built
|
||||
list does not crash later. The newly created RRset is
|
||||
linked after creation has succeeded. Thanks to Qifan Zhang,
|
||||
Palo Alto Networks, for the report.
|
||||
- Fix that dnscrypt configuration does not crash, due to
|
||||
inconsistency between secret and public keys. Also
|
||||
duplicate files are skipped. Thanks to Qifan Zhang, Palo
|
||||
Alto Networks, for the report.
|
||||
- Fix locking in libunbound ub_ctx_set_event call.
|
||||
Thanks to Qifan Zhang, Palo Alto Networks, for the report.
|
||||
- Fix that libunbound pipe functions fail with error after
|
||||
an event base is set. Thanks to Qifan Zhang, Palo Alto
|
||||
Networks, for the report.
|
||||
- Fix for neater solution to clear log thread id after
|
||||
worker init failure. Thanks to Qifan Zhang, Palo Alto
|
||||
Networks, for the report.
|
||||
- Fix incorrect cleanup after an allocation failure for
|
||||
a delegation point. Thanks to Qifan Zhang, Palo Alto
|
||||
Networks, for the report.
|
||||
- Fix that after malloc failure in find_tag_datas, the
|
||||
local_alias is cleaned up. Thanks to Qifan Zhang, Palo
|
||||
Alto Networks, for the report.
|
||||
- Fix that after shared memory cannot be created, from
|
||||
`shm-enable`, the server does not crash. Thanks to Qifan
|
||||
Zhang, Palo Alto Networks, for the report.
|
||||
- Fix incorrect cleanup after an allocation failure for
|
||||
a delegation point in a region. Thanks to Qifan Zhang,
|
||||
Palo Alto Networks, for the report.
|
||||
- Fix after malloc failure the rrset_insert_rr in
|
||||
localzone processing, during RPZ qname trigger processing,
|
||||
the RRset retains its previous data correcly. Thanks to
|
||||
Qifan Zhang, Palo Alto Networks, for the report.
|
||||
- Fix for #1462: Fix that auth primary host name lookup
|
||||
allows CNAMEs.
|
||||
|
||||
15 June 2026: Wouter
|
||||
- Fix to add `max-transfer-size` and `max-transfer-time` that
|
||||
limit auth-zone and rpz transfer amount and time taken.
|
||||
Default is disabled. This hardens against unbounded
|
||||
transfers. Thanks to Qifan Zhang, Palo Alto Networks,
|
||||
for the report.
|
||||
- Fix perform a full transfer every number of incremental
|
||||
transfers, to stop increasing memory usage, for rpz
|
||||
zones. Thanks to Qifan Zhang, Palo Alto Networks, for
|
||||
the report.
|
||||
- Fix assertion failure for long HTTP header that fills
|
||||
buffer. Thanks to Qifan Zhang, Palo Alto Networks, for
|
||||
the report.
|
||||
- Fix buffer overflow when configured with lower than
|
||||
default size and http transfer. Thanks to Qifan Zhang,
|
||||
Palo Alto Networks, for the report.
|
||||
- Fix that misconfigured `iter-scrub-ns: 0` causes request
|
||||
failures. Thanks to Qifan Zhang, Palo Alto Networks,
|
||||
for the report.
|
||||
- Fix that fast_reload when a zonemd verification lookup
|
||||
it in progress with subnet loaded, deregisters the
|
||||
callback. Thanks to Qifan Zhang, Palo Alto Networks,
|
||||
for the report.
|
||||
- Fix for fast_reload that removes an auth zone while its
|
||||
lookups are in progress, for a primary name. Also after the
|
||||
change, it no longer picks up the old results. Thanks to
|
||||
Qifan Zhang, Palo Alto Networks, for the report.
|
||||
- Fix integer overflow in infra-cache-max-rtt calculation.
|
||||
Thanks to Qifan Zhang, Palo Alto Networks, for the report.
|
||||
- Fix erroneous DNS error report values after bogus AAAA
|
||||
query caused error information that was not cleared by
|
||||
a successful A subquery. Thanks to Qifan Zhang, Palo Alto
|
||||
Networks, for the report.
|
||||
- Fix integer overflow for very high values of
|
||||
`sock-queue-timeout`. Thanks to Qifan Zhang, Palo Alto
|
||||
Networks, for the report.
|
||||
- Fix that fast_reload does not terminate the server for
|
||||
errors in config, for key files. Thanks to Qifan Zhang,
|
||||
Palo Alto Networks, for the report.
|
||||
- Fix log of an aliased qname, to not use freed region
|
||||
memory. Thanks to Qifan Zhang, Palo Alto Networks, for
|
||||
the report.
|
||||
- Fix DNAME synthesis from cache that keeps use of 0TTL
|
||||
entries in a sliding window. It did not surpass RRSIG
|
||||
expiry. Thanks to Qifan Zhang, Palo Alto Networks, for
|
||||
the report.
|
||||
- Fix misconfigured ipsecmod hook causing path name
|
||||
similarity with other file. The ipsecmod is changed for
|
||||
exec of the hook. The ipsecmod hook, if a script, has to
|
||||
start now with a line like `#!/bin/sh`. Thanks to Qifan
|
||||
Zhang, Palo Alto Networks, for the report.
|
||||
- Fix that dns64 bypasses rpz-passthru rule during
|
||||
synthesis. This restricted more than necessary. Thanks to
|
||||
Qifan Zhang, Palo Alto Networks, for the report.
|
||||
|
||||
12 June 2026: Wouter
|
||||
- Fix that for auth-zone and rpz zones the allow-notify
|
||||
addresses and netblocks are available from start, and
|
||||
fix the probe step skip.
|
||||
|
||||
11 June 2026: Wouter
|
||||
- Fix for #1306: configure detects specifically the call to
|
||||
SSL_set_quic_tls_early_data_enabled and
|
||||
SSL_set_quic_early_data_enabled, so the correct one is used.
|
||||
- Fix for #1306: configure checks if the ngtcp2_crypto_ossl
|
||||
header file is available, and prints an error otherwise.
|
||||
- Fix #1437: Fix compile with OpenSSL 4.0.1.
|
||||
- Fix compile for OpenSSL 1.0.2 and before in server cleanup.
|
||||
|
||||
10 June 2026: Wouter
|
||||
- Fix pythonmod script read for numeric overflow.
|
||||
- Fix warnings with gcc in compat/inet_pton.c.
|
||||
|
||||
9 June 2026: Wouter
|
||||
- Fix unit test for ecs to check for malloc success.
|
||||
|
||||
3 June 2026: Wouter
|
||||
- Fix that the processing of class responses does not have
|
||||
a heap use-after-free. That could happen if at least two
|
||||
distinct classes are configured for resolution. Thanks
|
||||
to Qifan Zhang, Palo Alto Networks for the report.
|
||||
In addition, thanks to Xin Wang, Jiapeng Li, and Jiajia
|
||||
Liu, Northwestern Polytechnical University, for also
|
||||
reporting this.
|
||||
- Fix negative cache to work with NSEC3 records without salt.
|
||||
Thanks to Xin Wang, Jiapeng Li, and Jiajia Liu, Northwestern
|
||||
Polytechnical University, for the report.
|
||||
- Fix parse of svcbparam ech, it had incorrect length. Thanks
|
||||
to Qifan Zhang, Palo Alto Networks for the report.
|
||||
- Fix that quotation and escaping works the same in auth-zone
|
||||
url content, as in the zonefile read. Thanks to Qifan Zhang,
|
||||
Palo Alto Networks for the report.
|
||||
- Fix ipset module to use larger domain name buffers, and
|
||||
check buffer lengths. Thanks to Qifan Zhang, Palo Alto
|
||||
Networks for the report.
|
||||
- Fix PROXYv2 header read and consume, it checks the header
|
||||
size. Thanks to Qifan Zhang, Palo Alto Networks for
|
||||
the report.
|
||||
- Fix negative cache NSEC3 nodata proof, to use the correct
|
||||
message size. Thanks to Qifan Zhang, Palo Alto Networks,
|
||||
for the report.
|
||||
- Fix fast_reload for when a ZONEMD lookup is in progress.
|
||||
Thanks to Qifan Zhang, Palo Alto Networks, for the report.
|
||||
- Fix that validation canonicalization of domain names
|
||||
in rdata checks for buffer bounds. Thanks to Qifan Zhang,
|
||||
Palo Alto Networks, for the report.
|
||||
- Fix that dump_cache has a larger buffer for records,
|
||||
and it checks that an owner name does not collide with BADRR
|
||||
on the input, and changes verbosity on the log of failure in
|
||||
rrset to string. Thanks to Qifan Zhang, Palo Alto Networks,
|
||||
for the report.
|
||||
- Fix that dns64 cleans up the allocated message if the adjust
|
||||
routines fail, and checks if there is a reply before cache
|
||||
store, also unbound checks if A and AAAA are malformed
|
||||
for auth-zones. Thanks to Qifan Zhang, Palo Alto Networks,
|
||||
for the report.
|
||||
|
||||
3 June 2026: Yorgos
|
||||
- Fix const as reported by newest compiler warnings.
|
||||
|
||||
29 May 2026: Wouter
|
||||
- Fix header_seen detection for trust anchor files, so that it
|
||||
detects the id line.
|
||||
- iana portlist updated.
|
||||
- Update icannbundle.pem certificates in unbound-anchor. It
|
||||
has the public keys for 2009 to 2029 and for 2025 to 2045.
|
||||
- Fix unit test to check for new icannbundle.pem.
|
||||
|
||||
28 May 2026: Wouter
|
||||
- Fix #1457: race condition causes segfault when starting
|
||||
threads.
|
||||
|
||||
27 May 2026: Wouter
|
||||
- Fix for autotrust state-file line overflow, that can give
|
||||
hold-down bypass. Thanks to Qifan Zhang, Palo Alto Networks,
|
||||
for the report.
|
||||
- Fix to limit the DSNS per-label walk in the iterator. Thanks
|
||||
to Qifan Zhang, Palo Alto Networks, for the report.
|
||||
- Fix that the ratelimit is decremented on successful
|
||||
referrals. Thanks to Qifan Zhang, Palo Alto Networks, for
|
||||
the report.
|
||||
- Fix that msgencode insert_query has the correct assertion,
|
||||
for a local_alias. Thanks to Qifan Zhang, Palo Alto Networks,
|
||||
for the report.
|
||||
- Fix to reset the tcp-timeout before applying a load based
|
||||
reduction. Thanks to Qifan Zhang, Palo Alto Networks, for the
|
||||
report.
|
||||
- Fix to decrement the per-netblock tcp connection limits, so
|
||||
it keeps usable. Thanks to Qifan Zhang, Palo Alto Networks,
|
||||
for the report.
|
||||
- Fix manual to document ratelimit, that it is for target
|
||||
nameservers for a domain, and keeps queries limited. Thanks
|
||||
to Qifan Zhang, Palo Alto Networks, for the report.
|
||||
- Fix, in depth, for respip rewrite of dns64 responses. Thanks
|
||||
to Qifan Zhang, Palo Alto Networks, for the report.
|
||||
- Fix that dns64 with subnetcache does not write ECS scoped
|
||||
answers to global cache. Thanks to Qifan Zhang, Palo Alto
|
||||
Networks, for the report.
|
||||
- Fix ipset module for name too long checks, race conditions
|
||||
on local name buffer, and for socket close race condition.
|
||||
Thanks to Qifan Zhang, Palo Alto Networks, for the report.
|
||||
- Fix that validator caps number of ANY RRsets it can
|
||||
validate, and the wait timer is shortened. Thanks to Qifan
|
||||
Zhang, Palo Alto Networks, for the report.
|
||||
- Fix analyzer warning in mesh_new_client.
|
||||
|
||||
26 May 2026: Wouter
|
||||
- Fix for mesh new client and mesh new callback to rollback the
|
||||
added address, tcp mesh state and callback when there is a failure
|
||||
to initialize. This fixes the mesh accounting of reply addresses.
|
||||
Thanks to Xin Wang, Jiapeng Li, and Jiajia Liu, Northwestern
|
||||
Polytechnical University, for the report
|
||||
|
||||
20 May 2026: Wouter
|
||||
- Fix CVE-2026-33278, Possible remote code execution during DNSSEC
|
||||
validation. Thanks to Qifan Zhang, Palo Alto Networks, for the report.
|
||||
@@ -27,6 +717,79 @@
|
||||
Networks, for the report.
|
||||
- Fix CVE-2026-44608, Use after free and crash in RPZ code. Thanks
|
||||
to Qifan Zhang, Palo Alto Networks, for the report.
|
||||
- Tag for 1.25.1 release, it contains the security fixes on 1.25.0.
|
||||
the code repository continues with in addition the previous fixes,
|
||||
for 1.25.2.
|
||||
- Unit test for CVE-2026-33278.
|
||||
- Unit test for CVE-2026-42944.
|
||||
- Unit test for CVE-2026-42959.
|
||||
- Unit test for CVE-2026-40622.
|
||||
- Unit test for CVE-2026-42960.
|
||||
- Fix in depth for serve-expired responses from cachedb, that it
|
||||
does not store bogus. Thanks to Qifan Zhang, Palo Alto Networks,
|
||||
for the report.
|
||||
- Fix lame server detection, for selfpointed glue records.
|
||||
Thanks to Shuhan Zhang, Dan Li, and Baojun Liu from Tsinghua
|
||||
University for the report.
|
||||
- Fix cleaning up DoH session. The same query can be on multiple
|
||||
streams in a session. Thanks to Qifan Zhang, Palo Alto Networks,
|
||||
for the report.
|
||||
- Fix for signed same-owner CNAME and ordinary RRset responses.
|
||||
Thanks to Xin Wang and Jiajia Liu, Northwestern Polytechnical
|
||||
University, for the report.
|
||||
|
||||
18 May 2026: Wouter
|
||||
- Fix for mixed class referrals, the resolver uses the query
|
||||
class. Thanks to Xin Wang and Jiajia Liu, Northwestern
|
||||
Polytechnical University, for the report.
|
||||
|
||||
15 May 2026: Wouter
|
||||
- Fix man page entry for so-sndbuf, it is for responses sent out.
|
||||
- Fix val_find_DS for robustness, to check the result of
|
||||
packet_rrset_copy_region before using it. Thanks to Xin Wang
|
||||
and Jiajia Liu, Northwestern Polytechnical University, for
|
||||
the report.
|
||||
- Fix that for dns64 answers, the AAAA query is checked to be
|
||||
DNSSEC validated, when DNSSEC is enabled. This improves
|
||||
the RFC6147 conformance of Unbound. Thanks to Xin Wang
|
||||
and Jiajia Liu, Northwestern Polytechnical University, for
|
||||
the report. In addition, thanks to Qifan Zhang, Palo Alto
|
||||
Networks, for reporting it.
|
||||
- Fix for allocation-failure hardening of rrset cache wildcard
|
||||
storage and canonical NSEC owner replacement. Thanks to Xin
|
||||
Wang and Jiajia Liu, Northwestern Polytechnical University,
|
||||
for the report.
|
||||
- Fix DNSSEC validation with libnettle for noncanonical RSA
|
||||
DNSKEYs with leading zeroes for n. Thanks to Xin Wang and
|
||||
Jiajia Liu, Northwestern Polytechnical University, for
|
||||
the report.
|
||||
- Fix DNSKEY size calculation for noncanonical RSA DNSKEYs
|
||||
with leading zeroes for n. Thanks to Xin Wang and Jiajia Liu,
|
||||
Northwestern Polytechnical University, for the report.
|
||||
|
||||
11 May 2026: Yorgos
|
||||
- Fix comment and verbose logging for EDNS fallback buffer size.
|
||||
|
||||
8 May 2026: Wouter
|
||||
- Fix to relax assertions after the TTL 0 handling change.
|
||||
This relaxes an assertion in cachedb (it fails instead),
|
||||
and for packet_rrset_copy_region.
|
||||
|
||||
7 May 2026: Wouter
|
||||
- Fix for Heap Out-of-Bounds Write via size_t-to-int Truncation
|
||||
in setup_if() - outside_network_create(). This fixes that
|
||||
large values for num_ports do not overflow and create
|
||||
invalid references after integer truncation. Thanks
|
||||
to Karnakar Reddy (@karnakarreddi) for the report.
|
||||
- Fix to clean up log ids after a failure to start a worker thread.
|
||||
|
||||
1 May 2026: Wouter
|
||||
- iana portlist updated.
|
||||
|
||||
29 April 2026: Wouter
|
||||
- tag for 1.25.0. The code repository continues with 1.25.1 in
|
||||
development.
|
||||
- Fix windows 64bit build for libssp dependency.
|
||||
|
||||
23 April 2026: Wouter
|
||||
- Merge #1441: Fix buffer overrun in
|
||||
|
||||
+23
-1
@@ -203,6 +203,12 @@ server:
|
||||
# protects against poison attempts.
|
||||
# iter-scrub-promiscuous: yes
|
||||
|
||||
# Limit on number of DNSSEC validation attempts for a query.
|
||||
# val-validation-attempts: 32
|
||||
|
||||
# Limit on number of DNSSEC hash attempts for a query.
|
||||
# val-hash-attempts: 32
|
||||
|
||||
# msec for waiting for an unknown server to reply. Increase if you
|
||||
# are behind a slow satellite link, to eg. 1128.
|
||||
# unknown-server-time-limit: 376
|
||||
@@ -582,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.
|
||||
@@ -728,7 +737,7 @@ server:
|
||||
# non-secure data. Useful to shield the users of this validator from
|
||||
# potential bogus data in the additional section. All unsigned data
|
||||
# in the additional section is removed from secure messages.
|
||||
# val-clean-additional: yes
|
||||
# val-clean-additional: no
|
||||
|
||||
# Turn permissive mode on to permit bogus messages. Thus, messages
|
||||
# for which security checks failed will be returned to clients,
|
||||
@@ -899,6 +908,10 @@ server:
|
||||
# that name
|
||||
# o block_a resolves all records normally but returns
|
||||
# NODATA for A queries and ignores local data for that name
|
||||
# o block_aaaa similarly to block_a, resolves all records normally but
|
||||
# returns NODATA for AAAA queries and ignores local data for that name
|
||||
# o block_a_wdata like block_a but uses local data if present.
|
||||
# o block_aaaa_wdata like block_aaaa but uses local data if present.
|
||||
# o always_null returns 0.0.0.0 or ::0 for any name in the zone.
|
||||
# o noview breaks out of that view towards global local-zones.
|
||||
#
|
||||
@@ -1158,6 +1171,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.
|
||||
@@ -1266,6 +1281,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
|
||||
@@ -1274,6 +1290,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
|
||||
@@ -1287,6 +1304,9 @@ remote-control:
|
||||
# zonemd-check: no
|
||||
# zonemd-reject-absence: no
|
||||
# zonefile: "example.org.zone"
|
||||
# max-transfer-size: 0
|
||||
# max-transfer-time: 0
|
||||
|
||||
|
||||
# Views
|
||||
# Create named views. Name must be unique.
|
||||
@@ -1453,3 +1473,5 @@ remote-control:
|
||||
# rpz-signal-nxdomain-ra: no
|
||||
# for-downstream: no
|
||||
# tags: "example"
|
||||
# max-transfer-size: 0
|
||||
# max-transfer-time: 0
|
||||
|
||||
@@ -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.
|
||||
|
||||
@@ -354,6 +354,8 @@ If the name already has no items, nothing happens.
|
||||
Often results in NXDOMAIN for the name (in a static zone), but if the name
|
||||
has become an empty nonterminal (there is still data in domain names below
|
||||
the removed name), NOERROR nodata answers are the result for that name.
|
||||
With a specific RR instead of a domain name, that specific record is
|
||||
removed from the local data, and not all the RR data.
|
||||
.UNINDENT
|
||||
.INDENT 0.0
|
||||
.TP
|
||||
|
||||
@@ -347,6 +347,8 @@ There are several commands that the server understands.
|
||||
Often results in NXDOMAIN for the name (in a static zone), but if the name
|
||||
has become an empty nonterminal (there is still data in domain names below
|
||||
the removed name), NOERROR nodata answers are the result for that name.
|
||||
With a specific RR instead of a domain name, that specific record is
|
||||
removed from the local data, and not all the RR data.
|
||||
|
||||
|
||||
@@UAHL@unbound-control.commands@local_zones@@
|
||||
|
||||
+152
-4
@@ -691,7 +691,7 @@ Default: 0 (use system value)
|
||||
.TP
|
||||
.B so\-sndbuf: \fI<number>\fP
|
||||
If not 0, then set the SO_SNDBUF socket option to get more buffer space on
|
||||
UDP port 53 outgoing queries.
|
||||
UDP port 53 outgoing responses.
|
||||
This for very busy servers handles spikes in answer traffic, otherwise:
|
||||
.INDENT 7.0
|
||||
.INDENT 3.5
|
||||
@@ -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
|
||||
@@ -2312,6 +2326,13 @@ The defensive action is to clear the rrset and message caches, hopefully
|
||||
flushing away any poison.
|
||||
A value of 10 million is suggested.
|
||||
.sp
|
||||
It is useful to add 0.0.0.0/8 and \(aq::\(aq to the
|
||||
\fI\%do\-not\-query\-address\fP list.
|
||||
Otherwise they may be answered, from localhost, and the different source
|
||||
makes an unwanted reply that unnecessarily ticks up.
|
||||
The \fI\%do\-not\-query\-localhost\fP
|
||||
option includes them, the zero subnets, when it is enabled.
|
||||
.sp
|
||||
Default: 0 (disabled)
|
||||
.UNINDENT
|
||||
.INDENT 0.0
|
||||
@@ -2329,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
|
||||
@@ -2362,6 +2386,8 @@ If yes, deny queries of type ANY with an empty response.
|
||||
If disabled, Unbound responds with a short list of resource records if some
|
||||
can be found in the cache and makes the upstream type ANY query if there
|
||||
are none.
|
||||
The option stops the DNSSEC validation from processing, possibly lengthy,
|
||||
ANY responses, when the option is enabled.
|
||||
.sp
|
||||
Default: no
|
||||
.UNINDENT
|
||||
@@ -2495,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
|
||||
@@ -2604,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
|
||||
@@ -2910,6 +2939,9 @@ The types are
|
||||
\fI\%inform_redirect\fP,
|
||||
\fI\%always_transparent\fP,
|
||||
\fI\%block_a\fP,
|
||||
\fI\%block_aaaa\fP,
|
||||
\fI\%block_a_wdata\fP,
|
||||
\fI\%block_aaaa_wdata\fP,
|
||||
\fI\%always_refuse\fP,
|
||||
\fI\%always_nxdomain\fP,
|
||||
\fI\%always_null\fP,
|
||||
@@ -3100,6 +3132,32 @@ use IPv6 protocol and avoid any queries to IPv4.
|
||||
.UNINDENT
|
||||
.INDENT 7.0
|
||||
.TP
|
||||
.B block_aaaa
|
||||
Like \fI\%transparent\fP or
|
||||
\fI\%block_a\fP, but
|
||||
ignores local data and resolves normally all query types excluding AAAA.
|
||||
For AAAA queries it unconditionally returns NODATA.
|
||||
Useful in cases when there is a need to explicitly force all apps to
|
||||
use IPv4 protocol and avoid any queries to IPv6.
|
||||
.UNINDENT
|
||||
.INDENT 7.0
|
||||
.TP
|
||||
.B block_a_wdata
|
||||
Like \fI\%block_a\fP, but
|
||||
uses local data if present.
|
||||
If there is local data that is returned, and it acts like transparent.
|
||||
For A queries it returns NODATA.
|
||||
.UNINDENT
|
||||
.INDENT 7.0
|
||||
.TP
|
||||
.B block_aaaa_wdata
|
||||
Like \fI\%block_aaaa\fP, but
|
||||
uses local data if present.
|
||||
If there is local data that is returned, and it acts like transparent.
|
||||
For AAAA queries it returns NODATA.
|
||||
.UNINDENT
|
||||
.INDENT 7.0
|
||||
.TP
|
||||
.B always_refuse
|
||||
Like \fI\%refuse\fP, but ignores
|
||||
local data and refuses the query.
|
||||
@@ -3567,6 +3625,18 @@ For example, 1000 may be a suitable value to stop the server from being
|
||||
overloaded with random names, and keeps unbound from sending traffic to the
|
||||
nameservers for those zones.
|
||||
.sp
|
||||
It is intended to count the number of queries towards the nameservers
|
||||
for the zone, and keep those queries limited.
|
||||
When there is a delegation that needs a lot of lookups, those are
|
||||
charged in the counters for the destination, the target name, of
|
||||
the NS records.
|
||||
Since that is where the nameserver lookup queries are sent to.
|
||||
That keeps the target, the victim domain, from having many queries.
|
||||
With the \fI\%ratelimit\-factor\fP, some
|
||||
genuine queries that are also made to the target zone, can filter
|
||||
through, and then end up in cache, where the genuine answers have
|
||||
a chance to collect, keeping up service to some extent.
|
||||
.sp
|
||||
\fBNOTE:\fP
|
||||
.INDENT 7.0
|
||||
.INDENT 3.5
|
||||
@@ -3829,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.
|
||||
@@ -4594,6 +4686,32 @@ If not given then no zonefile is used.
|
||||
If the file does not exist or is empty, Unbound will attempt to fetch zone
|
||||
data (eg. from the primary servers).
|
||||
.UNINDENT
|
||||
.INDENT 0.0
|
||||
.TP
|
||||
.B max\-transfer\-size: \fI<number>\fP
|
||||
Number of bytes size of the maximum zone transfer size.
|
||||
Larger transfers, over AXFR, IXFR and HTTP, are not allowed.
|
||||
A plain number is in bytes, append \(aqk\(aq, \(aqm\(aq or \(aqg\(aq for kilobytes, megabytes
|
||||
or gigabytes (1024*1024 bytes in a megabyte).
|
||||
The value \fB0\fP disables the feature.
|
||||
.sp
|
||||
Only consider for untrusted/misbehaving primaries that could hog resources
|
||||
and bring down the resolver.
|
||||
.sp
|
||||
Default: 0
|
||||
.UNINDENT
|
||||
.INDENT 0.0
|
||||
.TP
|
||||
.B max\-transfer\-time: \fI<msec>\fP
|
||||
Maximum time in milliseconds that a zone transfer is allowed to take from
|
||||
the start.
|
||||
The value \fB0\fP disables the feature.
|
||||
.sp
|
||||
Only consider for untrusted/misbehaving primaries that could hog resources
|
||||
and bring down the resolver.
|
||||
.sp
|
||||
Default: 0
|
||||
.UNINDENT
|
||||
.SH VIEW OPTIONS
|
||||
.sp
|
||||
These options are part of the \fBview:\fP section.
|
||||
@@ -5806,6 +5924,10 @@ from a webserver that would work.
|
||||
If you specify the hostname, you cannot use the domain from the zonefile,
|
||||
because it may not have that when retrieving that data, instead use a plain
|
||||
IP address to avoid a circular dependency on retrieving that IP address.
|
||||
.sp
|
||||
Every number of IXFR transfers, a full AXFR is performed.
|
||||
This is to consolidate the rpz memory, that would otherwise grow.
|
||||
The fixed value is after 5 IXFR transfers.
|
||||
.UNINDENT
|
||||
.INDENT 0.0
|
||||
.TP
|
||||
@@ -5928,6 +6050,32 @@ Enclose list of tags in quotes (\fB\(dq\(dq\fP) and put spaces between tags.
|
||||
If no tags are specified the policies from this section will be applied for
|
||||
all clients.
|
||||
.UNINDENT
|
||||
.INDENT 0.0
|
||||
.TP
|
||||
.B max\-transfer\-size: \fI<number>\fP
|
||||
Number of bytes size of the maximum zone transfer size.
|
||||
Larger transfers, over AXFR, IXFR and HTTP, are not allowed.
|
||||
A plain number is in bytes, append \(aqk\(aq, \(aqm\(aq or \(aqg\(aq for kilobytes, megabytes
|
||||
or gigabytes (1024*1024 bytes in a megabyte).
|
||||
The value \fB0\fP disables the feature.
|
||||
.sp
|
||||
Only consider for untrusted/misbehaving primaries that could hog resources
|
||||
and bring down the resolver.
|
||||
.sp
|
||||
Default: 0
|
||||
.UNINDENT
|
||||
.INDENT 0.0
|
||||
.TP
|
||||
.B max\-transfer\-time: \fI<msec>\fP
|
||||
Maximum time in milliseconds that a zone transfer is allowed to take from
|
||||
the start.
|
||||
The value \fB0\fP disables the feature.
|
||||
.sp
|
||||
Only consider for untrusted/misbehaving primaries that could hog resources
|
||||
and bring down the resolver.
|
||||
.sp
|
||||
Default: 0
|
||||
.UNINDENT
|
||||
.SH MEMORY CONTROL EXAMPLE
|
||||
.sp
|
||||
In the example config settings below memory usage is reduced.
|
||||
|
||||
+159
-4
@@ -642,7 +642,7 @@ These options are part of the ``server:`` section.
|
||||
|
||||
@@UAHL@unbound.conf@so-sndbuf@@: *<number>*
|
||||
If not 0, then set the SO_SNDBUF socket option to get more buffer space on
|
||||
UDP port 53 outgoing queries.
|
||||
UDP port 53 outgoing responses.
|
||||
This for very busy servers handles spikes in answer traffic, otherwise:
|
||||
|
||||
.. code-block:: text
|
||||
@@ -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
|
||||
@@ -2055,6 +2068,13 @@ These options are part of the ``server:`` section.
|
||||
flushing away any poison.
|
||||
A value of 10 million is suggested.
|
||||
|
||||
It is useful to add 0.0.0.0/8 and '::' to the
|
||||
:ref:`do-not-query-address<unbound.conf.do-not-query-address>` list.
|
||||
Otherwise they may be answered, from localhost, and the different source
|
||||
makes an unwanted reply that unnecessarily ticks up.
|
||||
The :ref:`do-not-query-localhost<unbound.conf.do-not-query-localhost>`
|
||||
option includes them, the zero subnets, when it is enabled.
|
||||
|
||||
Default: 0 (disabled)
|
||||
|
||||
|
||||
@@ -2070,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
|
||||
@@ -2100,6 +2123,8 @@ These options are part of the ``server:`` section.
|
||||
If disabled, Unbound responds with a short list of resource records if some
|
||||
can be found in the cache and makes the upstream type ANY query if there
|
||||
are none.
|
||||
The option stops the DNSSEC validation from processing, possibly lengthy,
|
||||
ANY responses, when the option is enabled.
|
||||
|
||||
Default: no
|
||||
|
||||
@@ -2217,6 +2242,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)
|
||||
|
||||
|
||||
@@ -2311,7 +2339,7 @@ These options are part of the ``server:`` section.
|
||||
Use this setting to protect the users that rely on this validator for
|
||||
authentication from potentially bad data in the additional section.
|
||||
|
||||
Default: yes
|
||||
Default: no
|
||||
|
||||
|
||||
@@UAHL@unbound.conf@val-log-level@@: *<number>*
|
||||
@@ -2583,6 +2611,9 @@ These options are part of the ``server:`` section.
|
||||
:ref:`inform_redirect<unbound.conf.local-zone.type.inform_redirect>`,
|
||||
:ref:`always_transparent<unbound.conf.local-zone.type.always_transparent>`,
|
||||
:ref:`block_a<unbound.conf.local-zone.type.block_a>`,
|
||||
:ref:`block_aaaa<unbound.conf.local-zone.type.block_aaaa>`,
|
||||
:ref:`block_a_wdata<unbound.conf.local-zone.type.block_a_wdata>`,
|
||||
:ref:`block_aaaa_wdata<unbound.conf.local-zone.type.block_aaaa_wdata>`,
|
||||
:ref:`always_refuse<unbound.conf.local-zone.type.always_refuse>`,
|
||||
:ref:`always_nxdomain<unbound.conf.local-zone.type.always_nxdomain>`,
|
||||
:ref:`always_null<unbound.conf.local-zone.type.always_null>`,
|
||||
@@ -2732,6 +2763,26 @@ These options are part of the ``server:`` section.
|
||||
Useful in cases when there is a need to explicitly force all apps to
|
||||
use IPv6 protocol and avoid any queries to IPv4.
|
||||
|
||||
@@UAHL@unbound.conf.local-zone.type@block_aaaa@@
|
||||
Like :ref:`transparent<unbound.conf.local-zone.type.transparent>` or
|
||||
:ref:`block_a<unbound.conf.local-zone.type.block_a>`, but
|
||||
ignores local data and resolves normally all query types excluding AAAA.
|
||||
For AAAA queries it unconditionally returns NODATA.
|
||||
Useful in cases when there is a need to explicitly force all apps to
|
||||
use IPv4 protocol and avoid any queries to IPv6.
|
||||
|
||||
@@UAHL@unbound.conf.local-zone.type@block_a_wdata@@
|
||||
Like :ref:`block_a<unbound.conf.local-zone.type.block_a>`, but
|
||||
uses local data if present.
|
||||
If there is local data that is returned, and it acts like transparent.
|
||||
For A queries it returns NODATA.
|
||||
|
||||
@@UAHL@unbound.conf.local-zone.type@block_aaaa_wdata@@
|
||||
Like :ref:`block_aaaa<unbound.conf.local-zone.type.block_aaaa>`, but
|
||||
uses local data if present.
|
||||
If there is local data that is returned, and it acts like transparent.
|
||||
For AAAA queries it returns NODATA.
|
||||
|
||||
@@UAHL@unbound.conf.local-zone.type@always_refuse@@
|
||||
Like :ref:`refuse<unbound.conf.local-zone.type.refuse>`, but ignores
|
||||
local data and refuses the query.
|
||||
@@ -3078,6 +3129,18 @@ These options are part of the ``server:`` section.
|
||||
overloaded with random names, and keeps unbound from sending traffic to the
|
||||
nameservers for those zones.
|
||||
|
||||
It is intended to count the number of queries towards the nameservers
|
||||
for the zone, and keep those queries limited.
|
||||
When there is a delegation that needs a lot of lookups, those are
|
||||
charged in the counters for the destination, the target name, of
|
||||
the NS records.
|
||||
Since that is where the nameserver lookup queries are sent to.
|
||||
That keeps the target, the victim domain, from having many queries.
|
||||
With the :ref:`ratelimit-factor<unbound.conf.ratelimit-factor>`, some
|
||||
genuine queries that are also made to the target zone, can filter
|
||||
through, and then end up in cache, where the genuine answers have
|
||||
a chance to collect, keeping up service to some extent.
|
||||
|
||||
.. note:: Configured forwarders are excluded from ratelimiting.
|
||||
|
||||
Default: 0
|
||||
@@ -3314,6 +3377,26 @@ These options are part of the ``server:`` section.
|
||||
Default: yes
|
||||
|
||||
|
||||
@@UAHL@unbound.conf@val-validation-attempts@@: *<number>*
|
||||
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.
|
||||
|
||||
Default: 32
|
||||
|
||||
|
||||
@@UAHL@unbound.conf@val-hash-attempts@@: *<number>*
|
||||
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.
|
||||
|
||||
Default: 32
|
||||
|
||||
|
||||
@@UAHL@unbound.conf@fast-server-permil@@: *<number>*
|
||||
Specify how many times out of 1000 to pick from the set of fastest servers.
|
||||
0 turns the feature off.
|
||||
@@ -3437,6 +3520,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
|
||||
@@ -4011,6 +4112,31 @@ fallback activates to fetch from the upstream instead of the SERVFAIL.
|
||||
If the file does not exist or is empty, Unbound will attempt to fetch zone
|
||||
data (eg. from the primary servers).
|
||||
|
||||
|
||||
@@UAHL@unbound.conf.auth@max-transfer-size@@: *<number>*
|
||||
Number of bytes size of the maximum zone transfer size.
|
||||
Larger transfers, over AXFR, IXFR and HTTP, are not allowed.
|
||||
A plain number is in bytes, append 'k', 'm' or 'g' for kilobytes, megabytes
|
||||
or gigabytes (1024*1024 bytes in a megabyte).
|
||||
The value ``0`` disables the feature.
|
||||
|
||||
Only consider for untrusted/misbehaving primaries that could hog resources
|
||||
and bring down the resolver.
|
||||
|
||||
Default: 0
|
||||
|
||||
|
||||
@@UAHL@unbound.conf.auth@max-transfer-time@@: *<msec>*
|
||||
Maximum time in milliseconds that a zone transfer is allowed to take from
|
||||
the start.
|
||||
The value ``0`` disables the feature.
|
||||
|
||||
Only consider for untrusted/misbehaving primaries that could hog resources
|
||||
and bring down the resolver.
|
||||
|
||||
Default: 0
|
||||
|
||||
|
||||
.. _unbound.conf.view:
|
||||
|
||||
View Options
|
||||
@@ -5091,6 +5217,10 @@ answer queries with that content.
|
||||
because it may not have that when retrieving that data, instead use a plain
|
||||
IP address to avoid a circular dependency on retrieving that IP address.
|
||||
|
||||
Every number of IXFR transfers, a full AXFR is performed.
|
||||
This is to consolidate the rpz memory, that would otherwise grow.
|
||||
The fixed value is after 5 IXFR transfers.
|
||||
|
||||
|
||||
@@UAHL@unbound.conf.rpz@master@@: *<IP address or host name>*
|
||||
Alternate syntax for :ref:`primary<unbound.conf.rpz.primary>`.
|
||||
@@ -5191,6 +5321,31 @@ answer queries with that content.
|
||||
If no tags are specified the policies from this section will be applied for
|
||||
all clients.
|
||||
|
||||
|
||||
@@UAHL@unbound.conf.rpz@max-transfer-size@@: *<number>*
|
||||
Number of bytes size of the maximum zone transfer size.
|
||||
Larger transfers, over AXFR, IXFR and HTTP, are not allowed.
|
||||
A plain number is in bytes, append 'k', 'm' or 'g' for kilobytes, megabytes
|
||||
or gigabytes (1024*1024 bytes in a megabyte).
|
||||
The value ``0`` disables the feature.
|
||||
|
||||
Only consider for untrusted/misbehaving primaries that could hog resources
|
||||
and bring down the resolver.
|
||||
|
||||
Default: 0
|
||||
|
||||
|
||||
@@UAHL@unbound.conf.rpz@max-transfer-time@@: *<msec>*
|
||||
Maximum time in milliseconds that a zone transfer is allowed to take from
|
||||
the start.
|
||||
The value ``0`` disables the feature.
|
||||
|
||||
Only consider for untrusted/misbehaving primaries that could hog resources
|
||||
and bring down the resolver.
|
||||
|
||||
Default: 0
|
||||
|
||||
|
||||
Memory Control Example
|
||||
----------------------
|
||||
|
||||
|
||||
@@ -459,6 +459,7 @@ addrtree_insert(struct addrtree *tree, const addrkey_t *addr,
|
||||
/* Data is stored in other leafnode */
|
||||
node = newnode;
|
||||
newnode = node_create(tree, elem, scope, ttl);
|
||||
if (!newnode) return;
|
||||
if (!edge_create(newnode, addr, sourcemask, node,
|
||||
index^1)) {
|
||||
clean_node(tree, newnode);
|
||||
|
||||
@@ -1015,6 +1015,7 @@ 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;
|
||||
}
|
||||
sq->wait_subquery_done = 0;
|
||||
qstate->ext_state[id] = module_finished;
|
||||
@@ -1094,6 +1095,7 @@ subnetmod_operate(struct module_qstate *qstate, enum module_ev event,
|
||||
qstate->env->cfg->prefetch)) {
|
||||
sne->num_msg_cache++;
|
||||
lock_rw_unlock(&sne->biglock);
|
||||
qstate->is_subnet_answer = 1;
|
||||
verbose(VERB_QUERY, "subnetcache: answered from cache");
|
||||
qstate->ext_state[id] = module_finished;
|
||||
|
||||
@@ -1165,6 +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);
|
||||
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(
|
||||
|
||||
@@ -100,6 +100,8 @@ ipsecmod_whitelist_apply_cfg(struct ipsecmod_env* ie,
|
||||
struct config_file* cfg)
|
||||
{
|
||||
ie->whitelist = rbtree_create(name_tree_compare);
|
||||
if (!ie->whitelist)
|
||||
return 0;
|
||||
if(!read_whitelist(ie->whitelist, cfg))
|
||||
return 0;
|
||||
name_tree_init_parents(ie->whitelist);
|
||||
|
||||
+91
-37
@@ -51,18 +51,28 @@
|
||||
#include "util/config_file.h"
|
||||
#include "services/cache/dns.h"
|
||||
#include "sldns/wire2str.h"
|
||||
#ifdef HAVE_SYS_WAIT_H
|
||||
#include <sys/wait.h>
|
||||
#endif
|
||||
|
||||
/** Apply configuration to ipsecmod module 'global' state. */
|
||||
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;
|
||||
}
|
||||
if(cfg->ipsecmod_whitelist &&
|
||||
!ipsecmod_whitelist_apply_cfg(ipsecmod_env, cfg))
|
||||
if(access(cfg->ipsecmod_hook, X_OK) != 0) {
|
||||
log_err("ipsecmod: ipsecmod-hook '%s' is not an executable file: %s",
|
||||
cfg->ipsecmod_hook, strerror(errno));
|
||||
return 0;
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
@@ -250,27 +260,16 @@ call_hook(struct module_qstate* qstate, struct ipsecmod_qstate* iq,
|
||||
struct ipsecmod_env* ATTR_UNUSED(ie))
|
||||
{
|
||||
size_t slen, tempdata_len, tempstring_len, i;
|
||||
char str[65535], *s, *tempstring;
|
||||
char qname_s[LDNS_MAX_DOMAINLEN*5+16], ttl_s[32], a_s[32768], k_s[32768];
|
||||
char *s, *tempstring;
|
||||
int w = 0, w_temp, qtype;
|
||||
struct ub_packed_rrset_key* rrset_key;
|
||||
struct packed_rrset_data* rrset_data;
|
||||
uint8_t *tempdata;
|
||||
pid_t pid;
|
||||
int st;
|
||||
char* argv[6];
|
||||
|
||||
/* Check if a shell is available */
|
||||
if(system(NULL) == 0) {
|
||||
log_err("ipsecmod: no shell available for ipsecmod-hook");
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Zero the buffer. */
|
||||
s = str;
|
||||
slen = sizeof(str);
|
||||
memset(s, 0, slen);
|
||||
|
||||
/* Copy the hook into the buffer. */
|
||||
w += sldns_str_print(&s, &slen, "%s", qstate->env->cfg->ipsecmod_hook);
|
||||
/* Put space into the buffer. */
|
||||
w += sldns_str_print(&s, &slen, " ");
|
||||
/* Copy the qname into the buffer. */
|
||||
tempstring = sldns_wire2str_dname(qstate->qinfo.qname,
|
||||
qstate->qinfo.qname_len);
|
||||
@@ -283,17 +282,24 @@ call_hook(struct module_qstate* qstate, struct ipsecmod_qstate* iq,
|
||||
free(tempstring);
|
||||
return 0;
|
||||
}
|
||||
w += sldns_str_print(&s, &slen, "\"%s\"", tempstring);
|
||||
if(strlen(tempstring)+1 > sizeof(qname_s)) {
|
||||
log_err("ipsecmod: string too long");
|
||||
free(tempstring);
|
||||
return 0;
|
||||
}
|
||||
snprintf(qname_s, sizeof(qname_s), "%s", tempstring);
|
||||
free(tempstring);
|
||||
/* Put space into the buffer. */
|
||||
w += sldns_str_print(&s, &slen, " ");
|
||||
|
||||
/* Copy the IPSECKEY TTL into the buffer. */
|
||||
rrset_data = (struct packed_rrset_data*)iq->ipseckey_rrset->entry.data;
|
||||
w += sldns_str_print(&s, &slen, "\"%ld\"", (long)rrset_data->ttl);
|
||||
/* Put space into the buffer. */
|
||||
w += sldns_str_print(&s, &slen, " ");
|
||||
snprintf(ttl_s, sizeof(ttl_s), "%ld", (long)rrset_data->ttl);
|
||||
|
||||
rrset_key = reply_find_answer_rrset(&qstate->return_msg->qinfo,
|
||||
qstate->return_msg->rep);
|
||||
if(!rrset_key) {
|
||||
log_err("ipsecmod: could not find answer rrset for A/AAAA");
|
||||
return 0;
|
||||
}
|
||||
/* Double check that the records are indeed A/AAAA.
|
||||
* This should never happen as this function is only executed for A/AAAA
|
||||
* queries but make sure we don't pass anything other than A/AAAA to the
|
||||
@@ -304,9 +310,15 @@ call_hook(struct module_qstate* qstate, struct ipsecmod_qstate* iq,
|
||||
return 0;
|
||||
}
|
||||
rrset_data = (struct packed_rrset_data*)rrset_key->entry.data;
|
||||
/* Copy the A/AAAA record(s) into the buffer. Start and end this section
|
||||
* with a double quote. */
|
||||
w += sldns_str_print(&s, &slen, "\"");
|
||||
if(!rrset_data) {
|
||||
log_err("ipsecmod: Answer has no data");
|
||||
return 0;
|
||||
}
|
||||
/* Copy the A/AAAA record(s) into the buffer. */
|
||||
w = 0;
|
||||
s = a_s;
|
||||
slen = sizeof(a_s);
|
||||
memset(s, 0, slen);
|
||||
for(i=0; i<rrset_data->count; i++) {
|
||||
if(i > 0) {
|
||||
/* Put space into the buffer. */
|
||||
@@ -322,7 +334,7 @@ call_hook(struct module_qstate* qstate, struct ipsecmod_qstate* iq,
|
||||
} else if((size_t)w_temp >= slen) {
|
||||
s = NULL; /* We do not want str to point outside of buffer. */
|
||||
slen = 0;
|
||||
log_err("ipsecmod: shell command too long");
|
||||
log_err("ipsecmod: command addr argument too long");
|
||||
return 0;
|
||||
} else {
|
||||
s += w_temp;
|
||||
@@ -330,12 +342,17 @@ call_hook(struct module_qstate* qstate, struct ipsecmod_qstate* iq,
|
||||
w += w_temp;
|
||||
}
|
||||
}
|
||||
w += sldns_str_print(&s, &slen, "\"");
|
||||
/* Put space into the buffer. */
|
||||
w += sldns_str_print(&s, &slen, " ");
|
||||
if(w >= (int)sizeof(a_s)) {
|
||||
log_err("ipsecmod: command addr argument too long");
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Copy the IPSECKEY record(s) into the buffer. Start and end this section
|
||||
* with a double quote. */
|
||||
w += sldns_str_print(&s, &slen, "\"");
|
||||
w = 0;
|
||||
s = k_s;
|
||||
slen = sizeof(k_s);
|
||||
memset(s, 0, slen);
|
||||
rrset_data = (struct packed_rrset_data*)iq->ipseckey_rrset->entry.data;
|
||||
for(i=0; i<rrset_data->count; i++) {
|
||||
if(i > 0) {
|
||||
@@ -362,15 +379,44 @@ call_hook(struct module_qstate* qstate, struct ipsecmod_qstate* iq,
|
||||
w += w_temp;
|
||||
}
|
||||
}
|
||||
w += sldns_str_print(&s, &slen, "\"");
|
||||
if(w >= (int)sizeof(str)) {
|
||||
log_err("ipsecmod: shell command too long");
|
||||
if(w >= (int)sizeof(k_s)) {
|
||||
log_err("ipsecmod: command ipseckey argument too long");
|
||||
return 0;
|
||||
}
|
||||
verbose(VERB_ALGO, "ipsecmod: shell command: '%s'", str);
|
||||
|
||||
/* ipsecmod-hook should return 0 on success. */
|
||||
if(system(str) != 0)
|
||||
/* exec the ipsecmod-hook */
|
||||
argv[0] = qstate->env->cfg->ipsecmod_hook;
|
||||
argv[1] = qname_s;
|
||||
argv[2] = ttl_s;
|
||||
argv[3] = a_s;
|
||||
argv[4] = k_s;
|
||||
argv[5] = NULL;
|
||||
verbose(VERB_ALGO, "ipsecmod: exec %s \"%s\" %s \"%s\" \"%s\"",
|
||||
argv[0], argv[1], argv[2], argv[3], argv[4]);
|
||||
if((pid = fork()) < 0) {
|
||||
log_err("ipsecmod: for exec, can not fork: %s",
|
||||
strerror(errno));
|
||||
return 0;
|
||||
}
|
||||
if(pid == 0) {
|
||||
if(execv(argv[0], argv) < 0)
|
||||
fprintf(stderr, "ipsecmod: execv: %s\n",
|
||||
strerror(errno));
|
||||
_exit(127);
|
||||
}
|
||||
while(1) {
|
||||
if(waitpid(pid, &st, 0) < 0) {
|
||||
if(errno == EINTR)
|
||||
continue;
|
||||
log_err("ipsecmod: wait_pid: %s", strerror(errno));
|
||||
}
|
||||
break;
|
||||
}
|
||||
if(!(WIFEXITED(st) && WEXITSTATUS(st) == 0)) {
|
||||
/* the command failed */
|
||||
return 0;
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
@@ -435,6 +481,12 @@ ipsecmod_handle_query(struct module_qstate* qstate,
|
||||
* ipsecmod_max_ttl. */
|
||||
rrset_key = reply_find_answer_rrset(&qstate->return_msg->qinfo,
|
||||
qstate->return_msg->rep);
|
||||
if(!rrset_key) {
|
||||
log_err("ipsecmod: reply-find-answer failed");
|
||||
errinf(qstate, "ipsecmod: reply-find-answer failed");
|
||||
ipsecmod_error(qstate, id);
|
||||
return;
|
||||
}
|
||||
rrset_data = (struct packed_rrset_data*)rrset_key->entry.data;
|
||||
if(rrset_data->ttl > (time_t)qstate->env->cfg->ipsecmod_max_ttl) {
|
||||
/* Update TTL for rrset to fixed value. */
|
||||
@@ -576,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(
|
||||
|
||||
+17
-14
@@ -143,7 +143,7 @@ static int add_to_ipset(filter_dev dev, const char *setname, const void *ipaddr,
|
||||
struct nlmsghdr *nlh;
|
||||
struct nfgenmsg *nfg;
|
||||
struct nlattr *nested[2];
|
||||
static char buffer[BUFF_LEN];
|
||||
char buffer[BUFF_LEN];
|
||||
|
||||
if (strlen(setname) >= IPSET_MAXNAMELEN) {
|
||||
errno = ENAMETOOLONG;
|
||||
@@ -208,13 +208,6 @@ ipset_add_rrset_data(struct ipset_env *ie,
|
||||
ret = add_to_ipset((filter_dev)ie->dev, setname, rr_data + 2, af);
|
||||
if (ret < 0) {
|
||||
log_err("ipset: could not add %s into %s", dname, setname);
|
||||
|
||||
#if HAVE_NET_PFVAR_H
|
||||
/* don't close as we might not be able to open again due to dropped privs */
|
||||
#else
|
||||
mnl_socket_close((filter_dev)ie->dev);
|
||||
ie->dev = NULL;
|
||||
#endif
|
||||
break;
|
||||
}
|
||||
}
|
||||
@@ -226,15 +219,15 @@ ipset_check_zones_for_rrset(struct module_env *env, struct ipset_env *ie,
|
||||
struct ub_packed_rrset_key *rrset, const char *qname, int qlen,
|
||||
const char *setname, int af)
|
||||
{
|
||||
static char dname[BUFF_LEN];
|
||||
char dname[LDNS_MAX_DOMAINLEN*4+16];
|
||||
const char *ds, *qs;
|
||||
int dlen, plen;
|
||||
|
||||
struct config_strlist *p;
|
||||
struct packed_rrset_data *d;
|
||||
|
||||
dlen = sldns_wire2str_dname_buf(rrset->rk.dname, rrset->rk.dname_len, dname, BUFF_LEN);
|
||||
if (dlen == 0) {
|
||||
dlen = sldns_wire2str_dname_buf(rrset->rk.dname, rrset->rk.dname_len, dname, sizeof(dname));
|
||||
if (dlen == 0 || dlen >= (int)sizeof(dname)) {
|
||||
log_err("bad domain name");
|
||||
return -1;
|
||||
}
|
||||
@@ -276,7 +269,7 @@ static int ipset_update(struct module_env *env, struct dns_msg *return_msg,
|
||||
const char *setname;
|
||||
struct ub_packed_rrset_key *rrset;
|
||||
int af;
|
||||
static char qname[BUFF_LEN];
|
||||
char qname[LDNS_MAX_DOMAINLEN*4+16];
|
||||
int qlen;
|
||||
|
||||
#ifdef HAVE_NET_PFVAR_H
|
||||
@@ -292,8 +285,8 @@ static int ipset_update(struct module_env *env, struct dns_msg *return_msg,
|
||||
#endif
|
||||
|
||||
qlen = sldns_wire2str_dname_buf(qinfo.qname, qinfo.qname_len,
|
||||
qname, BUFF_LEN);
|
||||
if(qlen == 0) {
|
||||
qname, sizeof(qname));
|
||||
if(qlen == 0 || qlen >= (int)sizeof(qname)) {
|
||||
log_err("bad domain name");
|
||||
return -1;
|
||||
}
|
||||
@@ -372,6 +365,16 @@ int ipset_init(struct module_env* env, int id) {
|
||||
|
||||
ipset_env->name_v4 = env->cfg->ipset_name_v4;
|
||||
ipset_env->name_v6 = env->cfg->ipset_name_v6;
|
||||
#ifndef HAVE_NET_PFVAR_H
|
||||
if (ipset_env->name_v4 && strlen(ipset_env->name_v4) >= IPSET_MAXNAMELEN) {
|
||||
log_err("ipset: name-v4 exceeds IPSET_MAXNAMELEN (%d)", IPSET_MAXNAMELEN);
|
||||
return 0;
|
||||
}
|
||||
if (ipset_env->name_v6 && strlen(ipset_env->name_v6) >= IPSET_MAXNAMELEN) {
|
||||
log_err("ipset: name-v6 exceeds IPSET_MAXNAMELEN (%d)", IPSET_MAXNAMELEN);
|
||||
return 0;
|
||||
}
|
||||
#endif
|
||||
|
||||
ipset_env->v4_enabled = !ipset_env->name_v4 || (strlen(ipset_env->name_v4) == 0) ? 0 : 1;
|
||||
ipset_env->v6_enabled = !ipset_env->name_v6 || (strlen(ipset_env->name_v6) == 0) ? 0 : 1;
|
||||
|
||||
+31
-24
@@ -118,10 +118,10 @@ delegpt_add_ns(struct delegpt* dp, struct regional* region, uint8_t* name,
|
||||
sizeof(struct delegpt_ns));
|
||||
if(!ns)
|
||||
return 0;
|
||||
ns->next = dp->nslist;
|
||||
ns->namelen = len;
|
||||
dp->nslist = ns;
|
||||
ns->name = regional_alloc_init(region, name, ns->namelen);
|
||||
if(!ns->name)
|
||||
return 0;
|
||||
ns->cache_lookup_count = 0;
|
||||
ns->resolved = 0;
|
||||
ns->got4 = 0;
|
||||
@@ -137,7 +137,9 @@ delegpt_add_ns(struct delegpt* dp, struct regional* region, uint8_t* name,
|
||||
} else {
|
||||
ns->tls_auth_name = NULL;
|
||||
}
|
||||
return ns->name != 0;
|
||||
ns->next = dp->nslist;
|
||||
dp->nslist = ns;
|
||||
return 1;
|
||||
}
|
||||
|
||||
struct delegpt_ns*
|
||||
@@ -223,11 +225,7 @@ delegpt_add_addr(struct delegpt* dp, struct regional* region,
|
||||
sizeof(struct delegpt_addr));
|
||||
if(!a)
|
||||
return 0;
|
||||
a->next_target = dp->target_list;
|
||||
dp->target_list = a;
|
||||
a->next_result = 0;
|
||||
a->next_usable = dp->usable_list;
|
||||
dp->usable_list = a;
|
||||
memcpy(&a->addr, addr, addrlen);
|
||||
a->addrlen = addrlen;
|
||||
a->attempts = 0;
|
||||
@@ -241,6 +239,10 @@ delegpt_add_addr(struct delegpt* dp, struct regional* region,
|
||||
} else {
|
||||
a->tls_auth_name = NULL;
|
||||
}
|
||||
a->next_target = dp->target_list;
|
||||
dp->target_list = a;
|
||||
a->next_usable = dp->usable_list;
|
||||
dp->usable_list = a;
|
||||
return 1;
|
||||
}
|
||||
|
||||
@@ -398,30 +400,33 @@ delegpt_count_missing_targets(struct delegpt* dp, int* alllame)
|
||||
|
||||
/** find NS rrset in given list */
|
||||
static struct ub_packed_rrset_key*
|
||||
find_NS(struct reply_info* rep, size_t from, size_t to)
|
||||
find_NS(struct reply_info* rep, size_t from, size_t to, uint16_t qclass)
|
||||
{
|
||||
size_t i;
|
||||
for(i=from; i<to; i++) {
|
||||
if(ntohs(rep->rrsets[i]->rk.type) == LDNS_RR_TYPE_NS)
|
||||
if(ntohs(rep->rrsets[i]->rk.type) == LDNS_RR_TYPE_NS &&
|
||||
ntohs(rep->rrsets[i]->rk.rrset_class) == qclass)
|
||||
return rep->rrsets[i];
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
struct delegpt*
|
||||
delegpt_from_message(struct dns_msg* msg, struct regional* region)
|
||||
delegpt_from_message(struct dns_msg* msg, struct regional* region, int port)
|
||||
{
|
||||
struct ub_packed_rrset_key* ns_rrset = NULL;
|
||||
struct delegpt* dp;
|
||||
size_t i;
|
||||
/* look for NS records in the authority section... */
|
||||
ns_rrset = find_NS(msg->rep, msg->rep->an_numrrsets,
|
||||
msg->rep->an_numrrsets+msg->rep->ns_numrrsets);
|
||||
msg->rep->an_numrrsets+msg->rep->ns_numrrsets,
|
||||
msg->qinfo.qclass);
|
||||
|
||||
/* In some cases (even legitimate, perfectly legal cases), the
|
||||
* NS set for the "referral" might be in the answer section. */
|
||||
if(!ns_rrset)
|
||||
ns_rrset = find_NS(msg->rep, 0, msg->rep->an_numrrsets);
|
||||
ns_rrset = find_NS(msg->rep, 0, msg->rep->an_numrrsets,
|
||||
msg->qinfo.qclass);
|
||||
|
||||
/* If there was no NS rrset in the authority section, then this
|
||||
* wasn't a referral message. (It might not actually be a
|
||||
@@ -436,7 +441,7 @@ delegpt_from_message(struct dns_msg* msg, struct regional* region)
|
||||
dp->has_parent_side_NS = 1; /* created from message */
|
||||
if(!delegpt_set_name(dp, region, ns_rrset->rk.dname))
|
||||
return NULL;
|
||||
if(!delegpt_rrset_add_ns(dp, region, ns_rrset, 0))
|
||||
if(!delegpt_rrset_add_ns(dp, region, ns_rrset, 0, port))
|
||||
return NULL;
|
||||
|
||||
/* add glue, A and AAAA in answer and additional section */
|
||||
@@ -447,10 +452,12 @@ delegpt_from_message(struct dns_msg* msg, struct regional* region)
|
||||
i < (msg->rep->an_numrrsets+msg->rep->ns_numrrsets))
|
||||
continue;
|
||||
|
||||
if(ntohs(s->rk.type) == LDNS_RR_TYPE_A) {
|
||||
if(ntohs(s->rk.type) == LDNS_RR_TYPE_A &&
|
||||
ntohs(s->rk.rrset_class) == msg->qinfo.qclass) {
|
||||
if(!delegpt_add_rrset_A(dp, region, s, 0, NULL))
|
||||
return NULL;
|
||||
} else if(ntohs(s->rk.type) == LDNS_RR_TYPE_AAAA) {
|
||||
} else if(ntohs(s->rk.type) == LDNS_RR_TYPE_AAAA &&
|
||||
ntohs(s->rk.rrset_class) == msg->qinfo.qclass) {
|
||||
if(!delegpt_add_rrset_AAAA(dp, region, s, 0, NULL))
|
||||
return NULL;
|
||||
}
|
||||
@@ -460,7 +467,7 @@ delegpt_from_message(struct dns_msg* msg, struct regional* region)
|
||||
|
||||
int
|
||||
delegpt_rrset_add_ns(struct delegpt* dp, struct regional* region,
|
||||
struct ub_packed_rrset_key* ns_rrset, uint8_t lame)
|
||||
struct ub_packed_rrset_key* ns_rrset, uint8_t lame, int port)
|
||||
{
|
||||
struct packed_rrset_data* nsdata = (struct packed_rrset_data*)
|
||||
ns_rrset->entry.data;
|
||||
@@ -475,7 +482,7 @@ delegpt_rrset_add_ns(struct delegpt* dp, struct regional* region,
|
||||
continue; /* bad format */
|
||||
/* add rdata of NS (= wirefmt dname), skip rdatalen bytes */
|
||||
if(!delegpt_add_ns(dp, region, nsdata->rr_data[i]+2, lame,
|
||||
NULL, UNBOUND_DNS_PORT))
|
||||
NULL, (port==-1?UNBOUND_DNS_PORT:port)))
|
||||
return 0;
|
||||
}
|
||||
return 1;
|
||||
@@ -534,7 +541,7 @@ delegpt_add_rrset(struct delegpt* dp, struct regional* region,
|
||||
if(!rrset)
|
||||
return 1;
|
||||
if(ntohs(rrset->rk.type) == LDNS_RR_TYPE_NS)
|
||||
return delegpt_rrset_add_ns(dp, region, rrset, lame);
|
||||
return delegpt_rrset_add_ns(dp, region, rrset, lame, -1);
|
||||
else if(ntohs(rrset->rk.type) == LDNS_RR_TYPE_A)
|
||||
return delegpt_add_rrset_A(dp, region, rrset, lame, additions);
|
||||
else if(ntohs(rrset->rk.type) == LDNS_RR_TYPE_AAAA)
|
||||
@@ -659,8 +666,6 @@ int delegpt_add_ns_mlc(struct delegpt* dp, uint8_t* name, uint8_t lame,
|
||||
free(ns);
|
||||
return 0;
|
||||
}
|
||||
ns->next = dp->nslist;
|
||||
dp->nslist = ns;
|
||||
ns->cache_lookup_count = 0;
|
||||
ns->resolved = 0;
|
||||
ns->got4 = 0;
|
||||
@@ -679,6 +684,8 @@ int delegpt_add_ns_mlc(struct delegpt* dp, uint8_t* name, uint8_t lame,
|
||||
} else {
|
||||
ns->tls_auth_name = NULL;
|
||||
}
|
||||
ns->next = dp->nslist;
|
||||
dp->nslist = ns;
|
||||
return 1;
|
||||
}
|
||||
|
||||
@@ -704,11 +711,7 @@ int delegpt_add_addr_mlc(struct delegpt* dp, struct sockaddr_storage* addr,
|
||||
a = (struct delegpt_addr*)malloc(sizeof(struct delegpt_addr));
|
||||
if(!a)
|
||||
return 0;
|
||||
a->next_target = dp->target_list;
|
||||
dp->target_list = a;
|
||||
a->next_result = 0;
|
||||
a->next_usable = dp->usable_list;
|
||||
dp->usable_list = a;
|
||||
memcpy(&a->addr, addr, addrlen);
|
||||
a->addrlen = addrlen;
|
||||
a->attempts = 0;
|
||||
@@ -724,6 +727,10 @@ int delegpt_add_addr_mlc(struct delegpt* dp, struct sockaddr_storage* addr,
|
||||
} else {
|
||||
a->tls_auth_name = NULL;
|
||||
}
|
||||
a->next_target = dp->target_list;
|
||||
dp->target_list = a;
|
||||
a->next_usable = dp->usable_list;
|
||||
dp->usable_list = a;
|
||||
return 1;
|
||||
}
|
||||
|
||||
|
||||
@@ -221,10 +221,11 @@ int delegpt_add_ns(struct delegpt* dp, struct regional* regional,
|
||||
* @param regional: where to allocate the info.
|
||||
* @param ns_rrset: NS rrset.
|
||||
* @param lame: rrset is lame, disprefer it.
|
||||
* @param port: port or -1 if not set.
|
||||
* @return 0 on alloc error.
|
||||
*/
|
||||
int delegpt_rrset_add_ns(struct delegpt* dp, struct regional* regional,
|
||||
struct ub_packed_rrset_key* ns_rrset, uint8_t lame);
|
||||
struct ub_packed_rrset_key* ns_rrset, uint8_t lame, int port);
|
||||
|
||||
/**
|
||||
* Add target address to the delegation point.
|
||||
@@ -365,11 +366,12 @@ size_t delegpt_count_targets(struct delegpt* dp);
|
||||
*
|
||||
* @param msg: the dns message, referral.
|
||||
* @param regional: where to allocate delegation point.
|
||||
* @param port: if not -1 specifies a port number.
|
||||
* @return new delegation point or NULL on alloc error, or if the
|
||||
* message was not appropriate.
|
||||
*/
|
||||
struct delegpt* delegpt_from_message(struct dns_msg* msg,
|
||||
struct regional* regional);
|
||||
struct regional* regional, int port);
|
||||
|
||||
/**
|
||||
* Mark negative return in delegation point for specific nameserver.
|
||||
|
||||
@@ -132,6 +132,18 @@ donotq_apply_cfg(struct iter_donotq* dq, struct config_file* cfg)
|
||||
if(cfg->do_ip6) {
|
||||
if(!donotq_str_cfg(dq, "::1"))
|
||||
return 0;
|
||||
if(!donotq_str_cfg(dq, "::ffff:127.0.0.0/104"))
|
||||
return 0;
|
||||
}
|
||||
/* RFC 1122 3.2.1.3 / RFC 6890 / RFC 4291 2.5.2: not valid as
|
||||
* destination; on Linux these route to the local host. */
|
||||
if(!donotq_str_cfg(dq, "0.0.0.0/8"))
|
||||
return 0;
|
||||
if(cfg->do_ip6) {
|
||||
if(!donotq_str_cfg(dq, "::"))
|
||||
return 0;
|
||||
if(!donotq_str_cfg(dq, "::ffff:0:0/96"))
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
addr_tree_init_parents(&dq->tree);
|
||||
|
||||
@@ -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* 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;
|
||||
@@ -122,10 +124,24 @@ response_type_from_server(int rdset,
|
||||
|
||||
/* If the message is NXDOMAIN, then it answers the question. */
|
||||
if(FLAGS_GET_RCODE(msg->rep->flags) == LDNS_RCODE_NXDOMAIN) {
|
||||
if(msg->rep->an_numrrsets == 0 &&
|
||||
msg->rep->ns_numrrsets == 0 &&
|
||||
msg_lame_empty)
|
||||
return RESPONSE_TYPE_LAME;
|
||||
/* make sure its not recursive when we don't want it to */
|
||||
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];
|
||||
@@ -143,6 +159,10 @@ response_type_from_server(int rdset,
|
||||
if(FLAGS_GET_RCODE(msg->rep->flags) != LDNS_RCODE_NOERROR)
|
||||
return RESPONSE_TYPE_THROWAWAY;
|
||||
|
||||
if(msg->rep->an_numrrsets == 0 && msg->rep->ns_numrrsets == 0 &&
|
||||
msg_lame_empty)
|
||||
return RESPONSE_TYPE_LAME;
|
||||
|
||||
/* Note: TC bit has already been handled */
|
||||
|
||||
if(dp) {
|
||||
@@ -154,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
|
||||
@@ -189,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;
|
||||
}
|
||||
|
||||
@@ -206,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;
|
||||
}
|
||||
}
|
||||
@@ -249,13 +275,16 @@ response_type_from_server(int rdset,
|
||||
* which gives ns==zone delegation from cache
|
||||
* without AA bit as well, with nodata nosoa*/
|
||||
/* real answer must be +AA and SOA RFC(2308),
|
||||
* so this is wrong, and we SERVFAIL it if
|
||||
* this is the only possible reply, if it
|
||||
* is misdeployed the THROWAWAY makes us pick
|
||||
* the next server from the selection */
|
||||
if(msg->rep->an_numrrsets==0 &&
|
||||
* this is picked up as lame_referral by the
|
||||
* sanitize step, so it can spot if there
|
||||
* was data in the answer section before
|
||||
* removal. If such data is then removed we
|
||||
* do not want to turn that answer into lame.
|
||||
* But if it was not there, it can be lame. */
|
||||
if(msg_lame_referral &&
|
||||
msg->rep->an_numrrsets==0 &&
|
||||
!(msg->rep->flags&BIT_AA) && !rdset)
|
||||
return RESPONSE_TYPE_THROWAWAY;
|
||||
return RESPONSE_TYPE_LAME;
|
||||
return RESPONSE_TYPE_ANSWER;
|
||||
}
|
||||
/* If we are getting a referral upwards (or to
|
||||
|
||||
@@ -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,15 +116,21 @@ 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.
|
||||
* @param empty_nodata_found: flag to keep track of empty nodata detection.
|
||||
* @param msg_lame_empty: The scrubber indicates that this empty message
|
||||
* 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* empty_nodata_found, int msg_lame_empty, int msg_lame_referral,
|
||||
struct config_file* cfg);
|
||||
|
||||
#endif /* ITERATOR_ITER_RESPTYPE_H */
|
||||
|
||||
+120
-8
@@ -294,7 +294,14 @@ synth_cname_rrset(uint8_t** sname, size_t* snamelen, uint8_t* alias,
|
||||
if(ttl_t > MAX_TTL) ttl_t = MAX_TTL;
|
||||
ttl = (uint32_t)ttl_t;
|
||||
sldns_write_uint32(cn->rr_first->ttl_data, ttl);
|
||||
sldns_write_uint32(rrset->rr_first->ttl_data, ttl);
|
||||
/* Do NOT write the clamp back into the packet buffer:
|
||||
* parse_packet already sized every name from the original
|
||||
* bytes and rdata_copy re-walks them trusting those sizes;
|
||||
* mutating packet bytes between the walks breaks that
|
||||
* invariant (compression pointers can target these TTL
|
||||
* bytes). The DNAME rrset receives the same clamp at store
|
||||
* time in rdata_copy, so the DNAME and the synthesized
|
||||
* CNAME still carry equal TTLs in the cache. */
|
||||
}
|
||||
sldns_write_uint16(cn->rr_first->ttl_data+4, aliaslen);
|
||||
memmove(cn->rr_first->ttl_data+6, alias, aliaslen);
|
||||
@@ -316,6 +323,20 @@ synth_cname_rrset(uint8_t** sname, size_t* snamelen, uint8_t* alias,
|
||||
return cn;
|
||||
}
|
||||
|
||||
/** Check if the packet has type NS in answer or authority section */
|
||||
static int
|
||||
pkt_contains_ns(struct msg_parse* msg)
|
||||
{
|
||||
struct rrset_parse* rrset;
|
||||
for(rrset = msg->rrset_first; rrset; rrset = rrset->rrset_all_next) {
|
||||
if(rrset->type == LDNS_RR_TYPE_NS &&
|
||||
(rrset->section == LDNS_SECTION_ANSWER ||
|
||||
rrset->section == LDNS_SECTION_AUTHORITY))
|
||||
return 1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
/** check if DNAME applies to a name */
|
||||
static int
|
||||
pkt_strict_sub(sldns_buffer* pkt, uint8_t* sname, uint8_t* dr)
|
||||
@@ -394,6 +415,8 @@ shorten_rrset(sldns_buffer* pkt, struct rrset_parse* rrset, int count)
|
||||
struct rr_parse* rr = rrset->rr_first, *prev = NULL;
|
||||
if(!rr)
|
||||
return;
|
||||
if(count < 1)
|
||||
return; /* cannot leave a still-linked rrset_parse with rr_count == 0 */
|
||||
for(i=0; i<count; i++) {
|
||||
prev = rr;
|
||||
rr = rr->next;
|
||||
@@ -478,6 +501,7 @@ scrub_normalize(sldns_buffer* pkt, struct msg_parse* msg,
|
||||
size_t snamelen = qinfo->qname_len;
|
||||
struct rrset_parse* rrset, *prev, *nsset=NULL;
|
||||
int cname_length = 0; /* number of CNAMEs, or DNAMEs */
|
||||
int has_answer = 0; /* if answer section contains nonCNAME,nonDNAME */
|
||||
|
||||
if(FLAGS_GET_RCODE(msg->flags) != LDNS_RCODE_NOERROR &&
|
||||
FLAGS_GET_RCODE(msg->flags) != LDNS_RCODE_NXDOMAIN &&
|
||||
@@ -500,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;
|
||||
@@ -519,6 +543,11 @@ scrub_normalize(sldns_buffer* pkt, struct msg_parse* msg,
|
||||
(unsigned)rrset->rr_count);
|
||||
return 0;
|
||||
}
|
||||
if(has_answer) {
|
||||
remove_rrset("normalize: removing DNAME redirection after answer:",
|
||||
pkt, msg, prev, &rrset);
|
||||
continue;
|
||||
}
|
||||
if(!synth_cname(sname, snamelen, rrset, alias,
|
||||
&aliaslen, pkt)) {
|
||||
verbose(VERB_ALGO, "synthesized CNAME "
|
||||
@@ -569,6 +598,11 @@ scrub_normalize(sldns_buffer* pkt, struct msg_parse* msg,
|
||||
if(rrset->type == LDNS_RR_TYPE_CNAME) {
|
||||
struct rrset_parse* nx = rrset->rrset_all_next;
|
||||
uint8_t* oldsname = sname;
|
||||
if(has_answer) {
|
||||
remove_rrset("normalize: removing redirection after answer:",
|
||||
pkt, msg, prev, &rrset);
|
||||
continue;
|
||||
}
|
||||
cname_length++;
|
||||
/* see if the next one is a DNAME, if so, swap them */
|
||||
if(nx && nx->section == LDNS_SECTION_ANSWER &&
|
||||
@@ -621,6 +655,9 @@ scrub_normalize(sldns_buffer* pkt, struct msg_parse* msg,
|
||||
if(rrset->type == LDNS_RR_TYPE_NS &&
|
||||
rrset->rr_count > env->cfg->iter_scrub_ns) {
|
||||
shorten_rrset(pkt, rrset, env->cfg->iter_scrub_ns);
|
||||
} else if(rrset->type == LDNS_RR_TYPE_DS &&
|
||||
rrset->rr_count > env->cfg->iter_scrub_ns) {
|
||||
shorten_rrset(pkt, rrset, env->cfg->iter_scrub_ns);
|
||||
}
|
||||
prev = rrset;
|
||||
rrset = rrset->rrset_all_next;
|
||||
@@ -640,6 +677,9 @@ scrub_normalize(sldns_buffer* pkt, struct msg_parse* msg,
|
||||
if(rrset->type == LDNS_RR_TYPE_NS &&
|
||||
rrset->rr_count > env->cfg->iter_scrub_ns) {
|
||||
shorten_rrset(pkt, rrset, env->cfg->iter_scrub_ns);
|
||||
} else if(rrset->type == LDNS_RR_TYPE_DS &&
|
||||
rrset->rr_count > env->cfg->iter_scrub_ns) {
|
||||
shorten_rrset(pkt, rrset, env->cfg->iter_scrub_ns);
|
||||
}
|
||||
|
||||
/* Mark the additional names from relevant rrset as OK. */
|
||||
@@ -647,6 +687,7 @@ scrub_normalize(sldns_buffer* pkt, struct msg_parse* msg,
|
||||
* will be removed by sanitize, so no additional for them */
|
||||
if(dname_pkt_compare(pkt, qinfo->qname, rrset->dname) == 0)
|
||||
mark_additional_rrset(pkt, msg, rrset);
|
||||
has_answer = 1;
|
||||
|
||||
prev = rrset;
|
||||
rrset = rrset->rrset_all_next;
|
||||
@@ -732,6 +773,11 @@ scrub_normalize(sldns_buffer* pkt, struct msg_parse* msg,
|
||||
"RRset:", pkt, msg, prev, &rrset);
|
||||
continue;
|
||||
}
|
||||
if(ntohs(rrset->rrset_class) != qinfo->qclass) {
|
||||
remove_rrset("normalize: removing other class "
|
||||
"RRset:", pkt, msg, prev, &rrset);
|
||||
continue;
|
||||
}
|
||||
if(nsset == NULL) {
|
||||
nsset = rrset;
|
||||
} else {
|
||||
@@ -758,6 +804,11 @@ scrub_normalize(sldns_buffer* pkt, struct msg_parse* msg,
|
||||
shorten_rrset(pkt, rrset, env->cfg->iter_scrub_ns);
|
||||
}
|
||||
}
|
||||
} else if(rrset->type==LDNS_RR_TYPE_DS) {
|
||||
if(rrset->rr_count > env->cfg->iter_scrub_ns) {
|
||||
shorten_rrset(pkt, rrset,
|
||||
env->cfg->iter_scrub_ns);
|
||||
}
|
||||
}
|
||||
/* if this is type DS and we query for type DS we just got
|
||||
* a referral answer for our type DS query, fix packet */
|
||||
@@ -860,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);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -968,18 +1019,28 @@ scrub_sanitize_rr_length(sldns_buffer* pkt, struct msg_parse* msg,
|
||||
* @param env: module environment with config and cache.
|
||||
* @param ie: iterator environment with private address data.
|
||||
* @param qstate: for setting errinf for EDE error messages.
|
||||
* @param pkt_before_NS: if the packet had type NS before scrub. If that
|
||||
* is removed now, that indicates this may have been lame.
|
||||
* @param msg_lame_empty: returned true if the empty packet is lame.
|
||||
* @param msg_lame_referral: returned true if the reply has a referral before
|
||||
* scrub.
|
||||
* @param rdset: if RD bit was sent in query sent by unbound.
|
||||
* @return 0 on error.
|
||||
*/
|
||||
static int
|
||||
scrub_sanitize(sldns_buffer* pkt, struct msg_parse* msg,
|
||||
struct query_info* qinfo, uint8_t* zonename, struct module_env* env,
|
||||
struct iter_env* ie, struct module_qstate* qstate)
|
||||
struct iter_env* ie, struct module_qstate* qstate,
|
||||
int pkt_before_NS, int* msg_lame_empty, int* msg_lame_referral,
|
||||
int rdset)
|
||||
{
|
||||
int del_addi = 0; /* if additional-holding rrsets are deleted, we
|
||||
do not trust the normalized additional-A-AAAA any more */
|
||||
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;
|
||||
|
||||
@@ -987,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)) {
|
||||
@@ -1002,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;
|
||||
}
|
||||
@@ -1130,6 +1213,21 @@ scrub_sanitize(sldns_buffer* pkt, struct msg_parse* msg,
|
||||
prev = rrset;
|
||||
rrset = rrset->rrset_all_next;
|
||||
}
|
||||
|
||||
/* If the packet is empty now, but it was not before. And there
|
||||
* was type NS in authority, then that indicates the answer is lame. */
|
||||
if(msg->rrset_first == NULL && pkt_before_NS) {
|
||||
*msg_lame_empty = 1;
|
||||
verbose(VERB_ALGO, "sanitize: empty message had referral to NS before, marked as lame");
|
||||
} else if(pkt_before_NS && msg->an_rrsets==0 &&
|
||||
!(msg->flags&BIT_AA) && !rdset) {
|
||||
/* If the packet is now a referral, not really a nodata,
|
||||
* then if it was also with an empty answer section before,
|
||||
* it is also lame. */
|
||||
*msg_lame_referral = 1;
|
||||
verbose(VERB_ALGO, "sanitize: message has referral not answer, marked as lame");
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
@@ -1137,11 +1235,15 @@ int
|
||||
scrub_message(sldns_buffer* pkt, struct msg_parse* msg,
|
||||
struct query_info* qinfo, uint8_t* zonename, struct regional* region,
|
||||
struct module_env* env, struct module_qstate* qstate,
|
||||
struct iter_env* ie)
|
||||
struct iter_env* ie, int* msg_lame_empty, int* msg_lame_referral,
|
||||
int rdset)
|
||||
{
|
||||
int pkt_before_NS;
|
||||
/* basic sanity checks */
|
||||
log_nametypeclass(VERB_ALGO, "scrub for", zonename, LDNS_RR_TYPE_NS,
|
||||
qinfo->qclass);
|
||||
*msg_lame_empty = 0;
|
||||
*msg_lame_referral = 0;
|
||||
if(msg->qdcount > 1)
|
||||
return 0;
|
||||
if( !(msg->flags&BIT_QR) )
|
||||
@@ -1166,11 +1268,21 @@ scrub_message(sldns_buffer* pkt, struct msg_parse* msg,
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* If the packet contains type NS in authority before scrub,
|
||||
* like a self referral. With the answer section empty, it
|
||||
* was not AA, the query was not sent with RD, with NS in auth,
|
||||
* and no SOA in auth. For a negative answer, type SOA is present.
|
||||
* This detects certain lameness if after has removed that. */
|
||||
pkt_before_NS = msg->an_rrsets == 0 &&
|
||||
!(msg->flags&BIT_AA) && !rdset &&
|
||||
pkt_contains_ns(msg) && !soa_in_auth(msg);
|
||||
|
||||
/* normalize the response, this cleans up the additional. */
|
||||
if(!scrub_normalize(pkt, msg, qinfo, region, env, zonename))
|
||||
return 0;
|
||||
/* delete all out-of-zone information */
|
||||
if(!scrub_sanitize(pkt, msg, qinfo, zonename, env, ie, qstate))
|
||||
if(!scrub_sanitize(pkt, msg, qinfo, zonename, env, ie, qstate,
|
||||
pkt_before_NS, msg_lame_empty, msg_lame_referral, rdset))
|
||||
return 0;
|
||||
return 1;
|
||||
}
|
||||
|
||||
@@ -62,11 +62,16 @@ struct module_qstate;
|
||||
* @param env: module environment with config settings and cache.
|
||||
* @param qstate: for setting errinf for EDE error messages.
|
||||
* @param ie: iterator module environment data.
|
||||
* @param msg_lame_empty: returned true if the empty packet is lame.
|
||||
* @param msg_lame_referral: returned true if the reply has a referral before
|
||||
* scrub.
|
||||
* @param rdset: if RD bit was sent in query sent by unbound.
|
||||
* @return: false if the message is total waste. true if scrubbed with success.
|
||||
*/
|
||||
int scrub_message(struct sldns_buffer* pkt, struct msg_parse* msg,
|
||||
struct query_info* qinfo, uint8_t* zonename, struct regional* regional,
|
||||
struct module_env* env, struct module_qstate* qstate,
|
||||
struct iter_env* ie);
|
||||
struct iter_env* ie, int* msg_lame_empty, int* msg_lame_referral,
|
||||
int rdset);
|
||||
|
||||
#endif /* ITERATOR_ITER_SCRUB_H */
|
||||
|
||||
+37
-3
@@ -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 */
|
||||
@@ -1313,7 +1313,8 @@ iter_lookup_parent_NS_from_cache(struct module_env* env, struct delegpt* dp,
|
||||
log_rrset_key(VERB_ALGO, "found parent-side NS in cache", akey);
|
||||
dp->has_parent_side_NS = 1;
|
||||
/* and mark the new names as lame */
|
||||
if(!delegpt_rrset_add_ns(dp, region, akey, 1)) {
|
||||
if(!delegpt_rrset_add_ns(dp, region, akey, 1,
|
||||
deleg_port_number(env))) {
|
||||
lock_rw_unlock(&akey->entry.lock);
|
||||
return 0;
|
||||
}
|
||||
@@ -1703,3 +1704,36 @@ iter_make_minimal(struct reply_info* rep)
|
||||
rep->ar_numrrsets = 0;
|
||||
rep->rrset_count -= rem;
|
||||
}
|
||||
|
||||
int
|
||||
deleg_port_number(struct module_env* env)
|
||||
{
|
||||
if(env->cfg->ssl_upstream)
|
||||
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);
|
||||
}
|
||||
|
||||
@@ -483,4 +483,10 @@ void limit_nsec_ttl(struct dns_msg* msg);
|
||||
*/
|
||||
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 */
|
||||
|
||||
+179
-41
@@ -81,7 +81,8 @@ int BLACKLIST_PENALTY = (120000*4);
|
||||
/** Timeout when only a single probe query per IP is allowed. */
|
||||
int PROBE_MAXRTO = PROBE_MAXRTO_DEFAULT; /* in msec */
|
||||
|
||||
static void target_count_increase_nx(struct iter_qstate* iq, int num);
|
||||
static void target_count_increase_nx(struct module_qstate* qstate,
|
||||
struct iter_qstate* iq, int num);
|
||||
|
||||
int
|
||||
iter_init(struct module_env* env, int id)
|
||||
@@ -250,7 +251,7 @@ error_supers(struct module_qstate* qstate, int id, struct module_qstate* super)
|
||||
if((dpns->got4 == 2 || (!ie->supports_ipv4 && !ie->nat64.use_nat64)) &&
|
||||
(dpns->got6 == 2 || !ie->supports_ipv6)) {
|
||||
dpns->resolved = 1; /* mark as failed */
|
||||
target_count_increase_nx(super_iq, 1);
|
||||
target_count_increase_nx(super, super_iq, 1);
|
||||
}
|
||||
}
|
||||
if(qstate->qinfo.qtype == LDNS_RR_TYPE_NS) {
|
||||
@@ -734,7 +735,7 @@ is_caps_whitelisted(struct iter_env* ie, struct iter_qstate* iq)
|
||||
* created for the parent query.
|
||||
*/
|
||||
static void
|
||||
target_count_create(struct iter_qstate* iq)
|
||||
target_count_create(struct module_qstate* qstate, struct iter_qstate* iq)
|
||||
{
|
||||
if(!iq->target_count) {
|
||||
iq->target_count = (int*)calloc(TARGET_COUNT_MAX, sizeof(int));
|
||||
@@ -742,33 +743,57 @@ target_count_create(struct iter_qstate* iq)
|
||||
if(iq->target_count) {
|
||||
iq->target_count[TARGET_COUNT_REF] = 1;
|
||||
iq->nxns_dp = (uint8_t**)calloc(1, sizeof(uint8_t*));
|
||||
/* continue global quota from where it was. */
|
||||
if(qstate->global_quota_reached >
|
||||
iq->target_count[TARGET_COUNT_GLOBAL_QUOTA])
|
||||
iq->target_count[TARGET_COUNT_GLOBAL_QUOTA] =
|
||||
qstate->global_quota_reached;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
target_count_increase(struct iter_qstate* iq, int num)
|
||||
target_count_store(struct module_qstate* qstate, struct iter_qstate* iq)
|
||||
{
|
||||
target_count_create(iq);
|
||||
if(iq->target_count) {
|
||||
/* By storing the global quota counter, it stays
|
||||
* there to be picked up if the module is restarted,
|
||||
* eg. due to a validator retry, and then the
|
||||
* target_count_create routine picks it up. */
|
||||
if(iq->target_count[TARGET_COUNT_GLOBAL_QUOTA] >
|
||||
qstate->global_quota_reached)
|
||||
qstate->global_quota_reached =
|
||||
iq->target_count[TARGET_COUNT_GLOBAL_QUOTA];
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
target_count_increase(struct module_qstate* qstate,
|
||||
struct iter_qstate* iq, int num)
|
||||
{
|
||||
target_count_create(qstate, iq);
|
||||
if(iq->target_count)
|
||||
iq->target_count[TARGET_COUNT_QUERIES] += num;
|
||||
iq->dp_target_count++;
|
||||
}
|
||||
|
||||
static void
|
||||
target_count_increase_nx(struct iter_qstate* iq, int num)
|
||||
target_count_increase_nx(struct module_qstate* qstate,
|
||||
struct iter_qstate* iq, int num)
|
||||
{
|
||||
target_count_create(iq);
|
||||
target_count_create(qstate, iq);
|
||||
if(iq->target_count)
|
||||
iq->target_count[TARGET_COUNT_NX] += num;
|
||||
}
|
||||
|
||||
static void
|
||||
target_count_increase_global_quota(struct iter_qstate* iq, int num)
|
||||
target_count_increase_global_quota(struct module_qstate* qstate,
|
||||
struct iter_qstate* iq, int num)
|
||||
{
|
||||
target_count_create(iq);
|
||||
target_count_create(qstate, iq);
|
||||
if(iq->target_count)
|
||||
iq->target_count[TARGET_COUNT_GLOBAL_QUOTA] += num;
|
||||
target_count_store(qstate, iq);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -861,7 +886,7 @@ generate_sub_request(uint8_t* qname, size_t qnamelen, uint16_t qtype,
|
||||
subiq = (struct iter_qstate*)subq->minfo[id];
|
||||
memset(subiq, 0, sizeof(*subiq));
|
||||
subiq->num_target_queries = 0;
|
||||
target_count_create(iq);
|
||||
target_count_create(qstate, iq);
|
||||
subiq->target_count = iq->target_count;
|
||||
if(iq->target_count) {
|
||||
iq->target_count[TARGET_COUNT_REF] ++; /* extra reference */
|
||||
@@ -1486,6 +1511,7 @@ processInitRequest(struct module_qstate* qstate, struct iter_qstate* iq,
|
||||
verbose(VERB_ALGO, "no-cache set, going to the network");
|
||||
qstate->no_cache_lookup = 1;
|
||||
qstate->no_cache_store = 1;
|
||||
qstate->fwd_stub_no_cache = 1;
|
||||
msg = NULL;
|
||||
} else if(qstate->blacklist) {
|
||||
/* if cache, or anything else, was blacklisted then
|
||||
@@ -1505,7 +1531,7 @@ processInitRequest(struct module_qstate* qstate, struct iter_qstate* iq,
|
||||
msg = val_neg_getmsg(qstate->env->neg_cache, &iq->qchase,
|
||||
qstate->region, qstate->env->rrset_cache,
|
||||
qstate->env->scratch_buffer,
|
||||
*qstate->env->now, 1/*add SOA*/, NULL,
|
||||
*qstate->env->now, 1/*add SOA*/, dpname,
|
||||
qstate->env->cfg);
|
||||
}
|
||||
/* item taken from cache does not match our query name, thus
|
||||
@@ -2234,7 +2260,7 @@ processLastResort(struct module_qstate* qstate, struct iter_qstate* iq,
|
||||
return error_response_cache(qstate, id, LDNS_RCODE_SERVFAIL);
|
||||
}
|
||||
iq->num_target_queries += qs;
|
||||
target_count_increase(iq, qs);
|
||||
target_count_increase(qstate, iq, qs);
|
||||
if(qs != 0) {
|
||||
qstate->ext_state[id] = module_wait_subquery;
|
||||
return 0; /* and wait for them */
|
||||
@@ -2290,7 +2316,7 @@ processLastResort(struct module_qstate* qstate, struct iter_qstate* iq,
|
||||
* lookups at a time. */
|
||||
verbose(VERB_ALGO, "try parent-side glue lookup");
|
||||
iq->num_target_queries += query_count;
|
||||
target_count_increase(iq, query_count);
|
||||
target_count_increase(qstate, iq, query_count);
|
||||
qstate->ext_state[id] = module_wait_subquery;
|
||||
return 0;
|
||||
}
|
||||
@@ -2310,7 +2336,7 @@ processLastResort(struct module_qstate* qstate, struct iter_qstate* iq,
|
||||
if(query_count != 0) { /* suspend to await results */
|
||||
verbose(VERB_ALGO, "try parent-side glue lookup");
|
||||
iq->num_target_queries += query_count;
|
||||
target_count_increase(iq, query_count);
|
||||
target_count_increase(qstate, iq, query_count);
|
||||
qstate->ext_state[id] = module_wait_subquery;
|
||||
return 0;
|
||||
}
|
||||
@@ -2366,6 +2392,12 @@ processDSNSFind(struct module_qstate* qstate, struct iter_qstate* iq, int id)
|
||||
|
||||
/* go up one (more) step, until we hit the dp, if so, end */
|
||||
dname_remove_label(&iq->dsns_point, &iq->dsns_point_len);
|
||||
if(++iq->dsns_count > MAX_DSNS_FIND_COUNT) {
|
||||
verbose(VERB_QUERY, "DS NS search exceeded %d labels",
|
||||
MAX_DSNS_FIND_COUNT);
|
||||
errinf(qstate, "DS NS search exceeded label limit");
|
||||
return error_response_cache(qstate, id, LDNS_RCODE_SERVFAIL);
|
||||
}
|
||||
if(query_dname_compare(iq->dsns_point, iq->dp->name) == 0) {
|
||||
/* there was no inbetween nameserver, use the old delegation
|
||||
* point again. And this time, because dsns_point is nonNULL
|
||||
@@ -2788,7 +2820,7 @@ processQueryTargets(struct module_qstate* qstate, struct iter_qstate* iq,
|
||||
return error_response_cache(qstate, id, LDNS_RCODE_SERVFAIL);
|
||||
}
|
||||
iq->num_target_queries += extra;
|
||||
target_count_increase(iq, extra);
|
||||
target_count_increase(qstate, iq, extra);
|
||||
if(iq->num_target_queries > 0) {
|
||||
/* wait to get all targets, we want to try em */
|
||||
verbose(VERB_ALGO, "wait for all targets for fallback");
|
||||
@@ -2839,7 +2871,7 @@ processQueryTargets(struct module_qstate* qstate, struct iter_qstate* iq,
|
||||
/* errors ignored, these targets are not strictly necessary for
|
||||
* this result, we do not have to reply with SERVFAIL */
|
||||
iq->num_target_queries += extra;
|
||||
target_count_increase(iq, extra);
|
||||
target_count_increase(qstate, iq, extra);
|
||||
}
|
||||
|
||||
/* Add the current set of unused targets to our queue. */
|
||||
@@ -2962,7 +2994,7 @@ processQueryTargets(struct module_qstate* qstate, struct iter_qstate* iq,
|
||||
LDNS_RCODE_SERVFAIL);
|
||||
}
|
||||
iq->num_target_queries += qs;
|
||||
target_count_increase(iq, qs);
|
||||
target_count_increase(qstate, iq, qs);
|
||||
}
|
||||
/* Since a target query might have been made, we
|
||||
* need to check again. */
|
||||
@@ -3022,7 +3054,7 @@ processQueryTargets(struct module_qstate* qstate, struct iter_qstate* iq,
|
||||
* this result, we do not have to reply with SERVFAIL */
|
||||
if(extra > 0) {
|
||||
iq->num_target_queries += extra;
|
||||
target_count_increase(iq, extra);
|
||||
target_count_increase(qstate, iq, extra);
|
||||
check_waiting_queries(iq, qstate, id);
|
||||
/* undo qname minimise step because we'll get back here
|
||||
* to do it again */
|
||||
@@ -3035,7 +3067,7 @@ processQueryTargets(struct module_qstate* qstate, struct iter_qstate* iq,
|
||||
}
|
||||
}
|
||||
|
||||
target_count_increase_global_quota(iq, 1);
|
||||
target_count_increase_global_quota(qstate, iq, 1);
|
||||
if(iq->target_count && iq->target_count[TARGET_COUNT_GLOBAL_QUOTA]
|
||||
> MAX_GLOBAL_QUOTA) {
|
||||
char s[LDNS_MAX_DOMAINLEN];
|
||||
@@ -3048,7 +3080,9 @@ processQueryTargets(struct module_qstate* qstate, struct iter_qstate* iq,
|
||||
|
||||
/* Do not check ratelimit for forwarding queries or if we already got a
|
||||
* pass. */
|
||||
sq_check_ratelimit = (!(iq->chase_flags & BIT_RD) && !iq->ratelimit_ok);
|
||||
sq_check_ratelimit = ((!(iq->chase_flags & BIT_RD) &&
|
||||
!iq->ratelimit_ok));
|
||||
iq->ratelimit_incremented = 0;
|
||||
/* We have a valid target. */
|
||||
if(verbosity >= VERB_QUERY) {
|
||||
log_query_info(VERB_QUERY, "sending query:", &iq->qinfo_out);
|
||||
@@ -3074,7 +3108,8 @@ processQueryTargets(struct module_qstate* qstate, struct iter_qstate* iq,
|
||||
iq->dp->name, iq->dp->namelen,
|
||||
(iq->dp->tcp_upstream || qstate->env->cfg->tcp_upstream),
|
||||
(iq->dp->ssl_upstream || qstate->env->cfg->ssl_upstream),
|
||||
target->tls_auth_name, qstate, &sq_was_ratelimited);
|
||||
target->tls_auth_name, qstate, &sq_was_ratelimited,
|
||||
&iq->ratelimit_incremented);
|
||||
if(!outq) {
|
||||
if(sq_was_ratelimited) {
|
||||
lock_basic_lock(&ie->queries_ratelimit_lock);
|
||||
@@ -3112,7 +3147,6 @@ find_NS(struct reply_info* rep, size_t from, size_t to)
|
||||
return NULL;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Process the query response. All queries end up at this state first. This
|
||||
* process generally consists of analyzing the response and routing the
|
||||
@@ -3154,7 +3188,8 @@ processQueryResponse(struct module_qstate* qstate, struct iter_qstate* iq,
|
||||
orig_empty_nodata_found = iq->empty_nodata_found;
|
||||
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->response, &iq->qinfo_out, iq->dp, &iq->empty_nodata_found,
|
||||
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;
|
||||
@@ -3267,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) {
|
||||
@@ -3432,7 +3508,14 @@ processQueryResponse(struct module_qstate* qstate, struct iter_qstate* iq,
|
||||
iq->deleg_msg = iq->response;
|
||||
/* Keep current delegation point for label comparison */
|
||||
old_dp = iq->dp;
|
||||
iq->dp = delegpt_from_message(iq->response, qstate->region);
|
||||
/* A referral reply is "pleasant", refund the
|
||||
* parent dp's rate charge before descending to the child. */
|
||||
if(iq->ratelimit_incremented)
|
||||
infra_ratelimit_dec(qstate->env->infra_cache,
|
||||
old_dp->name, old_dp->namelen,
|
||||
*qstate->env->now);
|
||||
iq->dp = delegpt_from_message(iq->response, qstate->region,
|
||||
deleg_port_number(qstate->env));
|
||||
if (qstate->env->cfg->qname_minimisation)
|
||||
iq->minimisation_state = INIT_MINIMISE_STATE;
|
||||
if(!iq->dp) {
|
||||
@@ -3709,7 +3792,8 @@ prime_supers(struct module_qstate* qstate, int id, struct module_qstate* forq)
|
||||
log_assert(qstate->is_priming || foriq->wait_priming_stub);
|
||||
log_assert(qstate->return_rcode == LDNS_RCODE_NOERROR);
|
||||
/* Convert our response to a delegation point */
|
||||
dp = delegpt_from_message(qstate->return_msg, forq->region);
|
||||
dp = delegpt_from_message(qstate->return_msg, forq->region,
|
||||
deleg_port_number(forq->env));
|
||||
if(!dp) {
|
||||
/* if there is no convertible delegation point, then
|
||||
* the ANSWER type was (presumably) a negative answer. */
|
||||
@@ -3760,7 +3844,8 @@ processPrimeResponse(struct module_qstate* qstate, int id)
|
||||
iq->response->rep->flags &= ~(BIT_RD|BIT_RA); /* ignore rec-lame */
|
||||
type = response_type_from_server(
|
||||
(int)((iq->chase_flags&BIT_RD) || iq->chase_to_rd),
|
||||
iq->response, &iq->qchase, iq->dp, NULL);
|
||||
iq->response, &iq->qchase, iq->dp, NULL, iq->msg_lame_empty,
|
||||
iq->msg_lame_referral, qstate->env->cfg);
|
||||
if(type == RESPONSE_TYPE_ANSWER) {
|
||||
qstate->return_rcode = LDNS_RCODE_NOERROR;
|
||||
qstate->return_msg = iq->response;
|
||||
@@ -3879,7 +3964,7 @@ processTargetResponse(struct module_qstate* qstate, int id,
|
||||
/* no new addresses, increase the nxns counter, like
|
||||
* this could be a list of wildcards with no new
|
||||
* addresses */
|
||||
target_count_increase_nx(foriq, 1);
|
||||
target_count_increase_nx(qstate, foriq, 1);
|
||||
}
|
||||
verbose(VERB_ALGO, "added target response");
|
||||
delegpt_log(VERB_ALGO, foriq->dp);
|
||||
@@ -3891,7 +3976,7 @@ processTargetResponse(struct module_qstate* qstate, int id,
|
||||
dpns->resolved = 1; /* fail the target */
|
||||
/* do not count cached answers */
|
||||
if(qstate->reply_origin && qstate->reply_origin->len != 0) {
|
||||
target_count_increase_nx(foriq, 1);
|
||||
target_count_increase_nx(qstate, foriq, 1);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -3910,26 +3995,49 @@ 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 */
|
||||
}
|
||||
|
||||
/* else, store as DP and continue at querytargets */
|
||||
foriq->state = QUERYTARGETS_STATE;
|
||||
foriq->dp = delegpt_from_message(qstate->return_msg, forq->region);
|
||||
foriq->dp = delegpt_from_message(qstate->return_msg, forq->region,
|
||||
deleg_port_number(forq->env));
|
||||
if(!foriq->dp) {
|
||||
log_err("out of memory in dsns dp alloc");
|
||||
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) */
|
||||
}
|
||||
|
||||
@@ -3973,7 +4081,7 @@ processClassResponse(struct module_qstate* qstate, int id,
|
||||
/* if there are records, copy RCODE */
|
||||
/* lower sec_state if this message is lower */
|
||||
if(from->rep->rrset_count != 0) {
|
||||
size_t n = from->rep->rrset_count+to->rep->rrset_count;
|
||||
size_t i, n = from->rep->rrset_count+to->rep->rrset_count;
|
||||
struct ub_packed_rrset_key** dest, **d;
|
||||
/* copy appropriate rcode */
|
||||
to->rep->flags = from->rep->flags;
|
||||
@@ -3995,24 +4103,49 @@ processClassResponse(struct module_qstate* qstate, int id,
|
||||
memcpy(dest, to->rep->rrsets, to->rep->an_numrrsets
|
||||
* sizeof(dest[0]));
|
||||
dest += to->rep->an_numrrsets;
|
||||
memcpy(dest, from->rep->rrsets, from->rep->an_numrrsets
|
||||
* sizeof(dest[0]));
|
||||
for(i=0; i<from->rep->an_numrrsets; i++) {
|
||||
dest[i] = packed_rrset_copy_region(
|
||||
from->rep->rrsets[i], forq->region, 0);
|
||||
if(!dest[i]) {
|
||||
log_err("malloc failed in collect ANY");
|
||||
foriq->state = FINISHED_STATE;
|
||||
return;
|
||||
}
|
||||
}
|
||||
dest += from->rep->an_numrrsets;
|
||||
/* copy NS */
|
||||
memcpy(dest, to->rep->rrsets+to->rep->an_numrrsets,
|
||||
to->rep->ns_numrrsets * sizeof(dest[0]));
|
||||
dest += to->rep->ns_numrrsets;
|
||||
memcpy(dest, from->rep->rrsets+from->rep->an_numrrsets,
|
||||
from->rep->ns_numrrsets * sizeof(dest[0]));
|
||||
for(i=0; i<from->rep->ns_numrrsets; i++) {
|
||||
dest[i] = packed_rrset_copy_region(
|
||||
from->rep->rrsets[
|
||||
from->rep->an_numrrsets+i],
|
||||
forq->region, 0);
|
||||
if(!dest[i]) {
|
||||
log_err("malloc failed in collect ANY");
|
||||
foriq->state = FINISHED_STATE;
|
||||
return;
|
||||
}
|
||||
}
|
||||
dest += from->rep->ns_numrrsets;
|
||||
/* copy AR */
|
||||
memcpy(dest, to->rep->rrsets+to->rep->an_numrrsets+
|
||||
to->rep->ns_numrrsets,
|
||||
to->rep->ar_numrrsets * sizeof(dest[0]));
|
||||
dest += to->rep->ar_numrrsets;
|
||||
memcpy(dest, from->rep->rrsets+from->rep->an_numrrsets+
|
||||
from->rep->ns_numrrsets,
|
||||
from->rep->ar_numrrsets * sizeof(dest[0]));
|
||||
for(i=0; i<from->rep->ar_numrrsets; i++) {
|
||||
dest[i] = packed_rrset_copy_region(
|
||||
from->rep->rrsets[
|
||||
from->rep->an_numrrsets+
|
||||
from->rep->ns_numrrsets+i],
|
||||
forq->region, 0);
|
||||
if(!dest[i]) {
|
||||
log_err("malloc failed in collect ANY");
|
||||
foriq->state = FINISHED_STATE;
|
||||
return;
|
||||
}
|
||||
}
|
||||
/* update counts */
|
||||
to->rep->rrsets = d;
|
||||
to->rep->an_numrrsets += from->rep->an_numrrsets;
|
||||
@@ -4116,6 +4249,7 @@ processFinished(struct module_qstate* qstate, struct iter_qstate* iq,
|
||||
iter_store_parentside_neg(qstate->env, &qstate->qinfo,
|
||||
iq->deleg_msg?iq->deleg_msg->rep:
|
||||
(iq->response?iq->response->rep:NULL));
|
||||
target_count_store(qstate, iq);
|
||||
if(!iq->response) {
|
||||
verbose(VERB_ALGO, "No response is set, servfail");
|
||||
errinf(qstate, "(no response found at query finish)");
|
||||
@@ -4369,7 +4503,10 @@ process_response(struct module_qstate* qstate, struct iter_qstate* iq,
|
||||
|
||||
/* normalize and sanitize: easy to delete items from linked lists */
|
||||
if(!scrub_message(pkt, prs, &iq->qinfo_out, iq->dp->name,
|
||||
qstate->env->scratch, qstate->env, qstate, ie)) {
|
||||
qstate->env->scratch, qstate->env, qstate, ie,
|
||||
&iq->msg_lame_empty, &iq->msg_lame_referral,
|
||||
(int)((iq->chase_flags&BIT_RD) || iq->chase_to_rd)
|
||||
)) {
|
||||
/* if 0x20 enabled, start fallback, but we have no message */
|
||||
if(event == module_event_capsfail && !iq->caps_fallback) {
|
||||
iq->caps_fallback = 1;
|
||||
@@ -4531,6 +4668,7 @@ iter_clear(struct module_qstate* qstate, int id)
|
||||
iq = (struct iter_qstate*)qstate->minfo[id];
|
||||
if(iq) {
|
||||
outbound_list_clear(&iq->outlist);
|
||||
target_count_store(qstate, iq);
|
||||
if(iq->target_count && --iq->target_count[TARGET_COUNT_REF] == 0) {
|
||||
free(iq->target_count);
|
||||
if(*iq->nxns_dp) free(*iq->nxns_dp);
|
||||
|
||||
@@ -104,6 +104,11 @@ extern int BLACKLIST_PENALTY;
|
||||
#define RTT_BAND 400
|
||||
/** Number of retries for empty nodata packets before it is accepted. */
|
||||
#define EMPTY_NODATA_RETRY_COUNT 2
|
||||
/** max label-strip iterations in DSNS_FIND_STATE (RFC 4035 4.2 parent-NS
|
||||
* search) before giving up; bounds upstream NS sends per client DS.
|
||||
* Means the max number of labels in grandchild to the grandparent zone that
|
||||
* are co-hosted. */
|
||||
#define MAX_DSNS_FIND_COUNT 20
|
||||
|
||||
/**
|
||||
* Iterator global state for nat64.
|
||||
@@ -375,6 +380,10 @@ struct iter_qstate {
|
||||
/** if true, already tested for ratelimiting and passed the test */
|
||||
int ratelimit_ok;
|
||||
|
||||
/** If the last query, that may be a referral, incremented the
|
||||
* ratelimit counter. */
|
||||
int ratelimit_incremented;
|
||||
|
||||
/**
|
||||
* The query must store NS records from referrals as parentside RRs
|
||||
* Enabled once it hits resolution problems, to throttle retries.
|
||||
@@ -399,6 +408,8 @@ struct iter_qstate {
|
||||
uint8_t* dsns_point;
|
||||
/** length of the dname in dsns_point */
|
||||
size_t dsns_point_len;
|
||||
/** number of label-strip iterations performed in DSNS_FIND_STATE */
|
||||
int dsns_count;
|
||||
|
||||
/**
|
||||
* expected dnssec information for this iteration step.
|
||||
@@ -434,6 +445,13 @@ struct iter_qstate {
|
||||
* already so that it is accepted later. */
|
||||
int empty_nodata_found;
|
||||
|
||||
/** Store if the answer was empty, but lame, before it became empty.*/
|
||||
int msg_lame_empty;
|
||||
|
||||
/** Store if the answer was a referral, to self, before scrub. So the
|
||||
* it is not some sort of answer. */
|
||||
int msg_lame_referral;
|
||||
|
||||
/** list of pending queries to authoritative servers. */
|
||||
struct outbound_list outlist;
|
||||
|
||||
|
||||
@@ -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 */
|
||||
@@ -167,6 +167,8 @@ struct ctx_query {
|
||||
ub_event_callback_type cb_event;
|
||||
/** for async query, the callback user arg */
|
||||
void* cb_arg;
|
||||
/** for async query the unique info */
|
||||
void* unique_info;
|
||||
|
||||
/** answer message, result from resolver lookup. */
|
||||
uint8_t* msg;
|
||||
|
||||
@@ -571,6 +571,8 @@ ub_ctx_async(struct ub_ctx* ctx, int dothread)
|
||||
int
|
||||
ub_poll(struct ub_ctx* ctx)
|
||||
{
|
||||
if(!ctx || ctx->event_base)
|
||||
return UB_INITFAIL;
|
||||
/* no need to hold lock while testing for readability. */
|
||||
return tube_poll(ctx->rr_pipe);
|
||||
}
|
||||
@@ -578,6 +580,8 @@ ub_poll(struct ub_ctx* ctx)
|
||||
int
|
||||
ub_fd(struct ub_ctx* ctx)
|
||||
{
|
||||
if(!ctx || ctx->event_base)
|
||||
return -1;
|
||||
return tube_read_fd(ctx->rr_pipe);
|
||||
}
|
||||
|
||||
@@ -672,6 +676,8 @@ ub_process(struct ub_ctx* ctx)
|
||||
int r;
|
||||
uint8_t* msg;
|
||||
uint32_t len;
|
||||
if(!ctx || ctx->event_base)
|
||||
return UB_INITFAIL;
|
||||
while(1) {
|
||||
msg = NULL;
|
||||
lock_basic_lock(&ctx->rrpipe_lock);
|
||||
@@ -700,6 +706,8 @@ ub_wait(struct ub_ctx* ctx)
|
||||
int r;
|
||||
uint8_t* msg;
|
||||
uint32_t len;
|
||||
if(!ctx || ctx->event_base)
|
||||
return UB_INITFAIL;
|
||||
/* this is basically the same loop as _process(), but with changes.
|
||||
* holds the rrpipe lock and waits with tube_wait */
|
||||
while(1) {
|
||||
@@ -837,6 +845,8 @@ ub_resolve_async(struct ub_ctx* ctx, const char* name, int rrtype,
|
||||
struct ctx_query* q;
|
||||
uint8_t* msg = NULL;
|
||||
uint32_t len = 0;
|
||||
if(!ctx || ctx->event_base)
|
||||
return UB_INITFAIL;
|
||||
|
||||
if(async_id)
|
||||
*async_id = 0;
|
||||
@@ -1467,8 +1477,15 @@ ub_ctx_set_event(struct ub_ctx* ctx, struct event_base* base) {
|
||||
|
||||
lock_basic_lock(&ctx->cfglock);
|
||||
/* destroy the current worker - safe to pass in NULL */
|
||||
|
||||
/* Unlock the cfglock during libworker_delete_event, since it
|
||||
* calls context_release_alloc, that wants to lock cfglock again.
|
||||
* Since the event base is used from one thread, the one that
|
||||
* called this function, it is safe to do so. */
|
||||
lock_basic_unlock(&ctx->cfglock);
|
||||
libworker_delete_event(ctx->event_worker);
|
||||
ctx->event_worker = NULL;
|
||||
lock_basic_lock(&ctx->cfglock);
|
||||
new_base = ub_libevent_event_base(base);
|
||||
if (new_base)
|
||||
ctx->event_base = new_base;
|
||||
|
||||
+22
-8
@@ -105,6 +105,7 @@ libworker_delete_env(struct libworker* w)
|
||||
SSL_CTX_free(w->sslctx);
|
||||
#endif
|
||||
outside_network_delete(w->back);
|
||||
shared_ports_delete(w->shared_ports);
|
||||
}
|
||||
|
||||
/** delete libworker struct */
|
||||
@@ -219,17 +220,25 @@ libworker_setup(struct ub_ctx* ctx, int is_bg, struct ub_event_base* eb)
|
||||
libworker_delete(w);
|
||||
return NULL;
|
||||
}
|
||||
if(!(w->shared_ports = shared_ports_create(cfg->out_ifs,
|
||||
cfg->num_out_ifs, cfg->do_ip4, cfg->do_ip6, ports, numports))) {
|
||||
if(!w->is_bg || w->is_bg_thread) {
|
||||
lock_basic_unlock(&ctx->cfglock);
|
||||
}
|
||||
libworker_delete(w);
|
||||
return NULL;
|
||||
}
|
||||
w->back = outside_network_create(w->base, cfg->msg_buffer_size,
|
||||
(size_t)cfg->outgoing_num_ports, cfg->out_ifs,
|
||||
cfg->num_out_ifs, cfg->do_ip4, cfg->do_ip6,
|
||||
cfg->do_tcp?cfg->outgoing_num_tcp:0, cfg->ip_dscp,
|
||||
w->env->infra_cache, w->env->rnd, cfg->use_caps_bits_for_id,
|
||||
ports, numports, cfg->unwanted_threshold,
|
||||
cfg->unwanted_threshold,
|
||||
cfg->outgoing_tcp_mss, &libworker_alloc_cleanup, w,
|
||||
cfg->do_udp || cfg->udp_upstream_without_downstream, w->sslctx,
|
||||
cfg->delay_close, cfg->tls_use_sni, NULL, cfg->udp_connect,
|
||||
cfg->max_reuse_tcp_queries, cfg->tcp_reuse_timeout,
|
||||
cfg->tcp_auth_query_timeout);
|
||||
cfg->tcp_auth_query_timeout, w->shared_ports);
|
||||
w->env->outnet = w->back;
|
||||
if(!w->is_bg || w->is_bg_thread) {
|
||||
lock_basic_unlock(&ctx->cfglock);
|
||||
@@ -642,7 +651,8 @@ int libworker_fg(struct ub_ctx* ctx, struct ctx_query* q)
|
||||
}
|
||||
/* process new query */
|
||||
if(!mesh_new_callback(w->env->mesh, &qinfo, qflags, &edns,
|
||||
w->back->udp_buff, qid, libworker_fg_done_cb, q, 0)) {
|
||||
w->back->udp_buff, qid, libworker_fg_done_cb, q, 0,
|
||||
&q->unique_info)) {
|
||||
free(qinfo.qname);
|
||||
return UB_NOMEM;
|
||||
}
|
||||
@@ -723,7 +733,8 @@ int libworker_attach_mesh(struct ub_ctx* ctx, struct ctx_query* q,
|
||||
if(async_id)
|
||||
*async_id = q->querynum;
|
||||
if(!mesh_new_callback(w->env->mesh, &qinfo, qflags, &edns,
|
||||
w->back->udp_buff, qid, libworker_event_done_cb, q, 0)) {
|
||||
w->back->udp_buff, qid, libworker_event_done_cb, q, 0,
|
||||
&q->unique_info)) {
|
||||
free(qinfo.qname);
|
||||
return UB_NOMEM;
|
||||
}
|
||||
@@ -861,7 +872,8 @@ handle_newq(struct libworker* w, uint8_t* buf, uint32_t len)
|
||||
q->w = w;
|
||||
/* process new query */
|
||||
if(!mesh_new_callback(w->env->mesh, &qinfo, qflags, &edns,
|
||||
w->back->udp_buff, qid, libworker_bg_done_cb, q, 0)) {
|
||||
w->back->udp_buff, qid, libworker_bg_done_cb, q, 0,
|
||||
&q->unique_info)) {
|
||||
add_bg_result(w, q, NULL, UB_NOMEM, NULL, 0);
|
||||
}
|
||||
free(qinfo.qname);
|
||||
@@ -879,7 +891,8 @@ struct outbound_entry* libworker_send_query(struct query_info* qinfo,
|
||||
int check_ratelimit,
|
||||
struct sockaddr_storage* addr, socklen_t addrlen, uint8_t* zone,
|
||||
size_t zonelen, int tcp_upstream, int ssl_upstream, char* tls_auth_name,
|
||||
struct module_qstate* q, int* was_ratelimited)
|
||||
struct module_qstate* q, int* was_ratelimited,
|
||||
int* ratelimit_incremented)
|
||||
{
|
||||
struct libworker* w = (struct libworker*)q->env->worker;
|
||||
struct outbound_entry* e = (struct outbound_entry*)regional_alloc(
|
||||
@@ -891,7 +904,7 @@ struct outbound_entry* libworker_send_query(struct query_info* qinfo,
|
||||
want_dnssec, nocaps, check_ratelimit, tcp_upstream, ssl_upstream,
|
||||
tls_auth_name, addr, addrlen, zone, zonelen, q,
|
||||
libworker_handle_service_reply, e, w->back->udp_buff, q->env,
|
||||
was_ratelimited);
|
||||
was_ratelimited, ratelimit_incremented);
|
||||
if(!e->qsent) {
|
||||
return NULL;
|
||||
}
|
||||
@@ -976,7 +989,8 @@ struct outbound_entry* worker_send_query(struct query_info* ATTR_UNUSED(qinfo),
|
||||
struct sockaddr_storage* ATTR_UNUSED(addr), socklen_t ATTR_UNUSED(addrlen),
|
||||
uint8_t* ATTR_UNUSED(zone), size_t ATTR_UNUSED(zonelen), int ATTR_UNUSED(tcp_upstream),
|
||||
int ATTR_UNUSED(ssl_upstream), char* ATTR_UNUSED(tls_auth_name),
|
||||
struct module_qstate* ATTR_UNUSED(q), int* ATTR_UNUSED(was_ratelimited))
|
||||
struct module_qstate* ATTR_UNUSED(q), int* ATTR_UNUSED(was_ratelimited),
|
||||
int* ATTR_UNUSED(ratelimit_incremented))
|
||||
{
|
||||
log_assert(0);
|
||||
return 0;
|
||||
|
||||
@@ -60,6 +60,7 @@ struct tube;
|
||||
struct sldns_buffer;
|
||||
struct ub_event_base;
|
||||
struct query_info;
|
||||
struct shared_ports;
|
||||
|
||||
/**
|
||||
* The library-worker status structure
|
||||
@@ -84,6 +85,8 @@ struct libworker {
|
||||
struct comm_base* base;
|
||||
/** the backside outside network interface to the auth servers */
|
||||
struct outside_network* back;
|
||||
/** shared ports structure */
|
||||
struct shared_ports* shared_ports;
|
||||
/** random() table for this worker. */
|
||||
struct ub_randstate* rndstate;
|
||||
/** sslcontext for SSL wrapped DNS over TCP queries */
|
||||
|
||||
@@ -0,0 +1,65 @@
|
||||
/*
|
||||
* libunbound/remote.h - prototypes for remote control 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
|
||||
* remote control service.
|
||||
*/
|
||||
|
||||
#ifndef LIBUNBOUND_REMOTE_H
|
||||
#define LIBUNBOUND_REMOTE_H
|
||||
|
||||
struct comm_reply;
|
||||
struct comm_point;
|
||||
|
||||
/** fast reload thread commands to remote service thread event callback */
|
||||
void fast_reload_service_cb(int fd, short bits, void* arg);
|
||||
|
||||
/** fast reload callback for the remote control client connection */
|
||||
int fast_reload_client_callback(struct comm_point* c, void* arg, int err,
|
||||
struct comm_reply* rep);
|
||||
|
||||
/** handle remote control accept callbacks */
|
||||
int remote_accept_callback(struct comm_point*, void*, int, struct comm_reply*);
|
||||
|
||||
/** handle remote control data callbacks */
|
||||
int remote_control_callback(struct comm_point*, void*, int, struct comm_reply*);
|
||||
|
||||
/** routine to printout option values over SSL */
|
||||
void remote_get_opt_ssl(char* line, void* arg);
|
||||
|
||||
#endif /* LIBUNBOUND_REMOTE_H */
|
||||
+8
-11
@@ -70,6 +70,8 @@ struct query_info;
|
||||
* @param q: which query state to reactivate upon return.
|
||||
* @param was_ratelimited: it will signal back if the query failed to pass the
|
||||
* ratelimit check.
|
||||
* @param ratelimit_incremented: set to true if the ratelimit counter
|
||||
* was increased.
|
||||
* @return: false on failure (memory or socket related). no query was
|
||||
* sent.
|
||||
*/
|
||||
@@ -78,7 +80,8 @@ struct outbound_entry* libworker_send_query(struct query_info* qinfo,
|
||||
int check_ratelimit,
|
||||
struct sockaddr_storage* addr, socklen_t addrlen, uint8_t* zone,
|
||||
size_t zonelen, int tcp_upstream, int ssl_upstream, char* tls_auth_name,
|
||||
struct module_qstate* q, int* was_ratelimited);
|
||||
struct module_qstate* q, int* was_ratelimited,
|
||||
int* ratelimit_incremented);
|
||||
|
||||
/** process incoming serviced query replies from the network */
|
||||
int libworker_handle_service_reply(struct comm_point* c, void* arg, int error,
|
||||
@@ -126,6 +129,8 @@ void worker_sighandler(int sig, void* arg);
|
||||
* @param q: which query state to reactivate upon return.
|
||||
* @param was_ratelimited: it will signal back if the query failed to pass the
|
||||
* ratelimit check.
|
||||
* @param ratelimit_incremented: set to true if the ratelimit counter
|
||||
* was increased.
|
||||
* @return: false on failure (memory or socket related). no query was
|
||||
* sent.
|
||||
*/
|
||||
@@ -134,7 +139,8 @@ struct outbound_entry* worker_send_query(struct query_info* qinfo,
|
||||
int check_ratelimit,
|
||||
struct sockaddr_storage* addr, socklen_t addrlen, uint8_t* zone,
|
||||
size_t zonelen, int tcp_upstream, int ssl_upstream, char* tls_auth_name,
|
||||
struct module_qstate* q, int* was_ratelimited);
|
||||
struct module_qstate* q, int* was_ratelimited,
|
||||
int* ratelimit_incremented);
|
||||
|
||||
/**
|
||||
* process control messages from the main thread. Frees the control
|
||||
@@ -171,13 +177,4 @@ void worker_start_accept(void* arg);
|
||||
/** stop accept callback handler */
|
||||
void worker_stop_accept(void* arg);
|
||||
|
||||
/** handle remote control accept callbacks */
|
||||
int remote_accept_callback(struct comm_point*, void*, int, struct comm_reply*);
|
||||
|
||||
/** handle remote control data callbacks */
|
||||
int remote_control_callback(struct comm_point*, void*, int, struct comm_reply*);
|
||||
|
||||
/** routine to printout option values over SSL */
|
||||
void remote_get_opt_ssl(char* line, void* arg);
|
||||
|
||||
#endif /* LIBUNBOUND_WORKER_H */
|
||||
|
||||
+10
-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
|
||||
@@ -466,9 +466,13 @@ if [ "$DOWIN" = "yes" ]; then
|
||||
|| error_cleanup "Could not configure"
|
||||
set +x
|
||||
else
|
||||
# Add -l:libssp:a to statically link libssp if possible.
|
||||
# Put it at the end of LIBS, to satisfy also linked in
|
||||
# dependencies.
|
||||
set -x
|
||||
$configure --enable-debug --enable-static-exe --disable-flto --disable-gost $* $cross_flag \
|
||||
|| error_cleanup "Could not configure"
|
||||
sed -i Makefile -e 's/^\(LIBS=.*\)$/\1 -l:libssp.a/'
|
||||
set +x
|
||||
fi
|
||||
info "Calling make"
|
||||
@@ -485,6 +489,7 @@ if [ "$DOWIN" = "yes" ]; then
|
||||
|| error_cleanup "Could not configure"
|
||||
set +x
|
||||
else
|
||||
# Do not add -l:libssp:a statically because it is a shared build.
|
||||
set -x
|
||||
$configure --enable-debug --disable-flto --disable-gost $* $shared_cross_flag \
|
||||
|| error_cleanup "Could not configure"
|
||||
@@ -598,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'
|
||||
@@ -616,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."
|
||||
|
||||
+16
-15
@@ -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) {
|
||||
@@ -729,7 +729,8 @@ struct module_env {
|
||||
int check_ratelimit,
|
||||
struct sockaddr_storage* addr, socklen_t addrlen,
|
||||
uint8_t* zone, size_t zonelen, int tcp_upstream, int ssl_upstream,
|
||||
char* tls_auth_name, struct module_qstate* q, int* was_ratelimited);
|
||||
char* tls_auth_name, struct module_qstate* q, int* was_ratelimited,
|
||||
int* ratelimit_incremented);
|
||||
void (*detach_subs)(struct module_qstate* qstate);
|
||||
int (*attach_sub)(struct module_qstate* qstate,
|
||||
struct query_info* qinfo, struct respip_client_info* cinfo,
|
||||
@@ -1626,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);
|
||||
@@ -1710,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);
|
||||
@@ -1764,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);
|
||||
@@ -1813,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);
|
||||
|
||||
+18
-5
@@ -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);
|
||||
@@ -487,10 +487,23 @@ int pythonmod_init(struct module_env* env, int id)
|
||||
/* for python 3.9 and newer */
|
||||
char* fstr = NULL;
|
||||
size_t flen = 0;
|
||||
long pos = 0;
|
||||
log_err("pythonmod: can't parse Python script %s", pe->fname);
|
||||
/* print the error to logs too, run it again */
|
||||
fseek(script_py, 0, SEEK_END);
|
||||
flen = (size_t)ftell(script_py);
|
||||
pos = ftell(script_py);
|
||||
if (pos == -1L) {
|
||||
log_err("ftell failed to print parse error: %s: %s",
|
||||
pe->fname, strerror(errno));
|
||||
goto fail_close_file;
|
||||
}
|
||||
flen = (size_t)pos;
|
||||
#ifdef SIZE_MAX
|
||||
if(flen > SIZE_MAX-2) {
|
||||
log_err("script file too large");
|
||||
goto fail_close_file;
|
||||
}
|
||||
#endif
|
||||
fstr = malloc(flen+1);
|
||||
if(!fstr) {
|
||||
log_err("malloc failure to print parse error");
|
||||
|
||||
+40
-22
@@ -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;
|
||||
@@ -899,27 +900,34 @@ respip_rewrite_reply(const struct query_info* qinfo,
|
||||
int rpz_cname_override = 0;
|
||||
char* log_name = NULL;
|
||||
|
||||
if(!cinfo)
|
||||
goto done;
|
||||
ctaglist = cinfo->taglist;
|
||||
ctaglen = cinfo->taglen;
|
||||
tag_actions = cinfo->tag_actions;
|
||||
tag_actions_size = cinfo->tag_actions_size;
|
||||
tag_datas = cinfo->tag_datas;
|
||||
tag_datas_size = cinfo->tag_datas_size;
|
||||
if(cinfo->view) {
|
||||
view = cinfo->view;
|
||||
lock_rw_rdlock(&view->lock);
|
||||
} else if(cinfo->view_name) {
|
||||
view = views_find_view(views, cinfo->view_name, 0);
|
||||
if(!view) {
|
||||
/* If the view no longer exists, the rewrite can not
|
||||
* be processed further. */
|
||||
verbose(VERB_ALGO, "respip: failed because view %s no "
|
||||
"longer exists", cinfo->view_name);
|
||||
return 0;
|
||||
if(!cinfo) {
|
||||
/* Internal mesh sub-query (e.g. dns64 A lookup): no
|
||||
* per-client view/tags, but global response-ip and RPZ
|
||||
* rpz-ip must still apply. */
|
||||
ctaglist = NULL; ctaglen = 0;
|
||||
tag_actions = NULL; tag_actions_size = 0;
|
||||
tag_datas = NULL; tag_datas_size = 0;
|
||||
} else {
|
||||
ctaglist = cinfo->taglist;
|
||||
ctaglen = cinfo->taglen;
|
||||
tag_actions = cinfo->tag_actions;
|
||||
tag_actions_size = cinfo->tag_actions_size;
|
||||
tag_datas = cinfo->tag_datas;
|
||||
tag_datas_size = cinfo->tag_datas_size;
|
||||
if(cinfo->view) {
|
||||
view = cinfo->view;
|
||||
lock_rw_rdlock(&view->lock);
|
||||
} else if(cinfo->view_name) {
|
||||
view = views_find_view(views, cinfo->view_name, 0);
|
||||
if(!view) {
|
||||
/* If the view no longer exists, the rewrite can not
|
||||
* be processed further. */
|
||||
verbose(VERB_ALGO, "respip: failed because view %s no "
|
||||
"longer exists", cinfo->view_name);
|
||||
return 0;
|
||||
}
|
||||
/* The view is rdlocked by views_find_view. */
|
||||
}
|
||||
/* The view is rdlocked by views_find_view. */
|
||||
}
|
||||
|
||||
log_assert(ipset);
|
||||
@@ -1114,7 +1122,13 @@ respip_operate(struct module_qstate* qstate, enum module_ev event, int id,
|
||||
if((qstate->qinfo.qtype == LDNS_RR_TYPE_A ||
|
||||
qstate->qinfo.qtype == LDNS_RR_TYPE_AAAA ||
|
||||
qstate->qinfo.qtype == LDNS_RR_TYPE_ANY) &&
|
||||
qstate->return_msg && qstate->return_msg->rep) {
|
||||
qstate->return_msg && qstate->return_msg->rep &&
|
||||
!(qstate->env->need_to_validate &&
|
||||
(!(qstate->query_flags & BIT_CD)
|
||||
|| qstate->env->cfg->ignore_cd) &&
|
||||
(qstate->return_msg->rep->security <= sec_status_bogus
|
||||
|| qstate->return_msg->rep->security ==
|
||||
sec_status_secure_sentinel_fail))) {
|
||||
struct reply_info* new_rep = qstate->return_msg->rep;
|
||||
struct ub_packed_rrset_key* alias_rrset = NULL;
|
||||
struct respip_action_info actinfo = {0, 0, 0, 0, NULL, 0, NULL};
|
||||
@@ -1151,8 +1165,10 @@ respip_operate(struct module_qstate* qstate, enum module_ev event, int id,
|
||||
* clients. */
|
||||
qstate->is_drop = 1;
|
||||
} else if(alias_rrset) {
|
||||
if(!generate_cname_request(qstate, alias_rrset))
|
||||
if(!generate_cname_request(qstate, alias_rrset)) {
|
||||
errinf(qstate, "Could not generate CNAME request");
|
||||
goto servfail;
|
||||
}
|
||||
next_state = module_wait_subquery;
|
||||
}
|
||||
qstate->return_msg->rep = new_rep;
|
||||
@@ -1166,6 +1182,7 @@ respip_operate(struct module_qstate* qstate, enum module_ev event, int id,
|
||||
servfail:
|
||||
qstate->return_rcode = LDNS_RCODE_SERVFAIL;
|
||||
qstate->return_msg = NULL;
|
||||
qstate->ext_state[id] = module_finished;
|
||||
}
|
||||
|
||||
int
|
||||
@@ -1262,6 +1279,7 @@ respip_inform_super(struct module_qstate* qstate, int id,
|
||||
return;
|
||||
|
||||
fail:
|
||||
errinf(super, "CNAME lookup failed");
|
||||
super->return_rcode = LDNS_RCODE_SERVFAIL;
|
||||
super->return_msg = NULL;
|
||||
return;
|
||||
|
||||
+1542
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,301 @@
|
||||
/*
|
||||
* 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;
|
||||
|
||||
/** 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.
|
||||
* @return false on failure.
|
||||
*/
|
||||
int auth_load_add_task_xfr(struct auth_xfer* xfr, struct worker* worker);
|
||||
|
||||
/**
|
||||
* 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);
|
||||
|
||||
/**
|
||||
* 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 */
|
||||
+1062
-258
File diff suppressed because it is too large
Load Diff
+99
-1
@@ -65,6 +65,7 @@ struct auth_probe;
|
||||
struct auth_transfer;
|
||||
struct auth_master;
|
||||
struct auth_chunk;
|
||||
struct auth_load_thread;
|
||||
|
||||
/**
|
||||
* Authoritative zones, shared.
|
||||
@@ -144,6 +145,14 @@ struct auth_zone {
|
||||
struct module_env* zonemd_callback_env;
|
||||
/** for the zonemd callback, the type of data looked up */
|
||||
uint16_t zonemd_callback_qtype;
|
||||
/** for the zonemd callback, the unique info */
|
||||
void* zonemd_callback_unique_info;
|
||||
/** if the zonemd callback should write to file */
|
||||
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 */
|
||||
@@ -153,6 +162,10 @@ struct auth_zone {
|
||||
struct auth_zone* rpz_az_next;
|
||||
/** previous auth zone containing RPZ data, or NULL */
|
||||
struct auth_zone* rpz_az_prev;
|
||||
/** The maximum auth zone transfer size, in bytes. */
|
||||
size_t max_transfer_size;
|
||||
/** The maximum auth zone transfer time taken, in msec. */
|
||||
int max_transfer_time;
|
||||
};
|
||||
|
||||
/**
|
||||
@@ -283,6 +296,15 @@ struct auth_xfer {
|
||||
* this is renewed every SOA probe and transfer. On zone load
|
||||
* from zonefile it is also set (with probe set soon to check) */
|
||||
time_t lease_time;
|
||||
|
||||
/** The maximum auth zone transfer size, in bytes. */
|
||||
size_t max_transfer_size;
|
||||
/** The maximum auth zone transfer time taken, in msec. */
|
||||
int max_transfer_time;
|
||||
/** the zone is an rpz zone */
|
||||
int is_rpz;
|
||||
/** the number of IXFRs since the last full transfer. */
|
||||
int num_ixfrs;
|
||||
};
|
||||
|
||||
/**
|
||||
@@ -331,6 +353,8 @@ struct auth_probe {
|
||||
|
||||
/** for the hostname lookups, which master is current */
|
||||
struct auth_master* lookup_target;
|
||||
/** for the lookup, the callback unique info */
|
||||
void* lookup_unique_info;
|
||||
/** are we looking up A or AAAA, first A, then AAAA (if ip6 enabled) */
|
||||
int lookup_aaaa;
|
||||
/** we only want to do lookups for making config work (for notify),
|
||||
@@ -379,12 +403,27 @@ struct auth_transfer {
|
||||
struct auth_chunk* chunks_first;
|
||||
/** last element in chunks list (to append new data at the end) */
|
||||
struct auth_chunk* chunks_last;
|
||||
/** running total of bytes held in chunks_first..chunks_last */
|
||||
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;
|
||||
|
||||
/** for the hostname lookups, which master is current */
|
||||
struct auth_master* lookup_target;
|
||||
/** for the lookup, the callback unique info */
|
||||
void* lookup_unique_info;
|
||||
/** are we looking up A or AAAA, first A, then AAAA (if ip6 enabled) */
|
||||
int lookup_aaaa;
|
||||
|
||||
@@ -518,7 +557,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.
|
||||
@@ -828,4 +875,55 @@ void auth_xfer_delete(struct auth_xfer* xfr);
|
||||
*/
|
||||
void xfr_disown_tasks(struct auth_xfer* xfr, struct worker* worker);
|
||||
|
||||
/** count number of open and closed parenthesis in a chunkline */
|
||||
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, 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
+23
-6
@@ -43,6 +43,7 @@
|
||||
#include "iterator/iter_utils.h"
|
||||
#include "validator/val_nsec.h"
|
||||
#include "validator/val_utils.h"
|
||||
#include "iterator/iter_utils.h"
|
||||
#include "services/cache/dns.h"
|
||||
#include "services/cache/rrset.h"
|
||||
#include "util/data/msgparse.h"
|
||||
@@ -94,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)
|
||||
@@ -115,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
|
||||
@@ -277,6 +281,8 @@ find_closest_of_type(struct module_env* env, uint8_t* qname, size_t qnamelen,
|
||||
|
||||
/* snip off front label */
|
||||
lablen = *qname;
|
||||
if(lablen == 0)
|
||||
break;
|
||||
qname += lablen + 1;
|
||||
qnamelen -= lablen + 1;
|
||||
}
|
||||
@@ -584,8 +590,12 @@ dns_cache_find_delegation(struct module_env* env, uint8_t* qname,
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
if(!delegpt_rrset_add_ns(dp, region, nskey, 0))
|
||||
if(!delegpt_rrset_add_ns(dp, region, nskey, 0,
|
||||
deleg_port_number(env))) {
|
||||
lock_rw_unlock(&nskey->entry.lock);
|
||||
log_err("find_delegation: addns out of memory");
|
||||
return NULL;
|
||||
}
|
||||
lock_rw_unlock(&nskey->entry.lock); /* first unlock before next lookup*/
|
||||
/* find and add DS/NSEC (if any) */
|
||||
if(msg)
|
||||
@@ -670,7 +680,7 @@ tomsg(struct module_env* env, struct query_info* q, struct reply_info* r,
|
||||
rrset_array_unlock(r->ref, r->rrset_count);
|
||||
return NULL;
|
||||
}
|
||||
if(r->security == sec_status_secure && !reply_all_rrsets_secure(r)) {
|
||||
if(r->security == sec_status_secure && !reply_an_ns_rrsets_secure(r)) {
|
||||
/* message rrsets have changed status, revalidate */
|
||||
rrset_array_unlock(r->ref, r->rrset_count);
|
||||
return NULL;
|
||||
@@ -780,11 +790,16 @@ synth_dname_msg(struct ub_packed_rrset_key* rrset, struct regional* region,
|
||||
uint8_t* newname, *dtarg = NULL;
|
||||
size_t newlen, dtarglen;
|
||||
time_t rr_ttl;
|
||||
int graceperiod = 0;
|
||||
if(TTL_IS_EXPIRED(d->ttl, now)) {
|
||||
/* Allow TTL=0 DNAME from upstream within grace period */
|
||||
if(!(rrset->rk.flags & PACKED_RRSET_UPSTREAM_0TTL))
|
||||
return NULL;
|
||||
rr_ttl = 0;
|
||||
/* Since PACKED_RRSET_UPSTREAM_0TTL set the flag that
|
||||
* the grace period has been applied, this stops the rrset
|
||||
* from getting stored back into the cache with a bigger TTL.*/
|
||||
graceperiod = 1;
|
||||
} else {
|
||||
rr_ttl = d->ttl - now;
|
||||
}
|
||||
@@ -812,6 +827,8 @@ synth_dname_msg(struct ub_packed_rrset_key* rrset, struct regional* region,
|
||||
msg->rep->rrsets[0] = packed_rrset_copy_region(rrset, region, now);
|
||||
if(!msg->rep->rrsets[0]) /* copy DNAME */
|
||||
return NULL;
|
||||
if(graceperiod)
|
||||
msg->rep->rrsets[0]->rk.flags |= PACKED_RRSET_0TTL_GRACE;
|
||||
/* synth CNAME rrset */
|
||||
get_cname_target(rrset, &dtarg, &dtarglen);
|
||||
if(!dtarg)
|
||||
@@ -1065,7 +1082,7 @@ dns_cache_lookup(struct module_env* env,
|
||||
if(env->cfg->harden_below_nxdomain) {
|
||||
while(!dname_is_root(k.qname)) {
|
||||
if(dpname && dpnamelen
|
||||
&& !dname_subdomain_c(k.qname, dpname))
|
||||
&& !dname_strict_subdomain_c(k.qname, dpname))
|
||||
break; /* no synth nxdomain above the stub */
|
||||
dname_remove_label(&k.qname, &k.qname_len);
|
||||
h = query_info_hash(&k, flags);
|
||||
@@ -1194,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
+73
-11
@@ -50,6 +50,7 @@
|
||||
#include "util/regional.h"
|
||||
#include "util/alloc.h"
|
||||
#include "util/net_help.h"
|
||||
#include "validator/val_utils.h"
|
||||
|
||||
void
|
||||
rrset_markdel(void* key)
|
||||
@@ -126,7 +127,8 @@ rrset_cache_touch(struct rrset_cache* r, struct ub_packed_rrset_key* key,
|
||||
|
||||
/** see if rrset needs to be updated in the cache */
|
||||
static int
|
||||
need_to_update_rrset(void* nd, void* cd, time_t timenow, int equal, int ns)
|
||||
need_to_update_rrset(void* nd, void* cd, time_t timenow, int equal, int ns,
|
||||
int a_aaaa)
|
||||
{
|
||||
struct packed_rrset_data* newd = (struct packed_rrset_data*)nd;
|
||||
struct packed_rrset_data* cached = (struct packed_rrset_data*)cd;
|
||||
@@ -151,9 +153,13 @@ need_to_update_rrset(void* nd, void* cd, time_t timenow, int equal, int ns)
|
||||
return 0;
|
||||
/* ghost-domain: never let an NS overwrite extend lifetime
|
||||
* past the entry it replaces, regardless of trust. */
|
||||
if(ns && !TTL_IS_EXPIRED(cached->ttl, timenow) &&
|
||||
/* Also for A/AAAA and it is glue. */
|
||||
if((ns ||
|
||||
(a_aaaa && cached->trust==rrset_trust_add_noAA))
|
||||
&& !TTL_IS_EXPIRED(cached->ttl, timenow) &&
|
||||
newd->ttl > cached->ttl) {
|
||||
size_t i;
|
||||
if(a_aaaa) newd->trust=rrset_trust_add_noAA;
|
||||
newd->ttl = cached->ttl;
|
||||
for(i=0; i<(newd->count+newd->rrsig_count); i++)
|
||||
if(newd->rr_ttl[i] > newd->ttl)
|
||||
@@ -209,6 +215,13 @@ rrset_cache_update(struct rrset_cache* r, struct rrset_ref* ref,
|
||||
int equal = 0;
|
||||
log_assert(ref->id != 0 && k->id != 0);
|
||||
log_assert(k->rk.dname != NULL);
|
||||
if((k->rk.flags&PACKED_RRSET_0TTL_GRACE) !=0) {
|
||||
log_nametypeclass(VERB_ALGO, "rrset store of PACKED_RRSET_0TTL_GRACE rrset skipped", k->rk.dname, rrset_type, ntohs(k->rk.rrset_class));
|
||||
ub_packed_rrset_parsedelete(k, alloc);
|
||||
return 0; /* Do not store 0TTL items after apply of
|
||||
the grace ttl amount.
|
||||
This means the ref was not changed by the call. */
|
||||
}
|
||||
/* looks up item with a readlock - no editing! */
|
||||
if((e=slabhash_lookup(&r->table, h, k, 0)) != 0) {
|
||||
/* return id and key as they will be used in the cache
|
||||
@@ -223,11 +236,16 @@ rrset_cache_update(struct rrset_cache* r, struct rrset_ref* ref,
|
||||
equal = rrsetdata_equal((struct packed_rrset_data*)k->entry.
|
||||
data, (struct packed_rrset_data*)e->data);
|
||||
if(!need_to_update_rrset(k->entry.data, e->data, timenow,
|
||||
equal, (rrset_type==LDNS_RR_TYPE_NS))) {
|
||||
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);
|
||||
@@ -255,12 +273,54 @@ 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,
|
||||
struct ub_packed_rrset_key* rrset)
|
||||
{
|
||||
struct packed_rrset_data* d = (struct packed_rrset_data*)
|
||||
rrset->entry.data;
|
||||
size_t i;
|
||||
if(!d || !d->rrsig_count)
|
||||
return 0;
|
||||
for(i=0; i<d->rrsig_count; i++) {
|
||||
uint8_t* sname = NULL;
|
||||
size_t slen = 0;
|
||||
rrsig_get_signer(d->rr_data[d->count+i], d->rr_len[d->count+i],
|
||||
&sname, &slen);
|
||||
if(!sname || !slen)
|
||||
return 0; /* malformed */
|
||||
if(!dname_subdomain_c(dname, sname))
|
||||
return 0; /* not a subdomain */
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
void rrset_cache_update_wildcard(struct rrset_cache* rrset_cache,
|
||||
struct ub_packed_rrset_key* rrset, uint8_t* ce, size_t ce_len,
|
||||
struct alloc_cache* alloc, time_t timenow)
|
||||
{
|
||||
struct rrset_ref ref;
|
||||
uint8_t wc_dname[LDNS_MAX_DOMAINLEN+3];
|
||||
uint8_t* new_dname;
|
||||
size_t new_dname_len;
|
||||
|
||||
/* See if the RRSIG signer name allows this wildcard,
|
||||
* the new rrset should fall within the zone of the RRSIG signer(s). */
|
||||
if(!dname_subdomain_rrsig_signers(ce, rrset)) {
|
||||
verbose(VERB_ALGO, "wildcard canonical parent outside signer authority");
|
||||
return;
|
||||
}
|
||||
|
||||
rrset = packed_rrset_copy_alloc(rrset, alloc, timenow);
|
||||
if(!rrset) {
|
||||
log_err("malloc failure in rrset_cache_update_wildcard");
|
||||
@@ -272,20 +332,22 @@ void rrset_cache_update_wildcard(struct rrset_cache* rrset_cache,
|
||||
wc_dname[1] = (uint8_t)'*';
|
||||
memmove(wc_dname+2, ce, ce_len);
|
||||
|
||||
free(rrset->rk.dname);
|
||||
rrset->rk.dname_len = ce_len + 2;
|
||||
rrset->rk.dname = (uint8_t*)memdup(wc_dname, rrset->rk.dname_len);
|
||||
if(!rrset->rk.dname) {
|
||||
alloc_special_release(alloc, rrset);
|
||||
new_dname_len = ce_len + 2;
|
||||
new_dname = (uint8_t*)memdup(wc_dname, new_dname_len);
|
||||
if(!new_dname) {
|
||||
ub_packed_rrset_parsedelete(rrset, alloc);
|
||||
log_err("memdup failure in rrset_cache_update_wildcard");
|
||||
return;
|
||||
}
|
||||
free(rrset->rk.dname);
|
||||
rrset->rk.dname = new_dname;
|
||||
rrset->rk.dname_len = new_dname_len;
|
||||
|
||||
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
|
||||
|
||||
+198
-84
@@ -42,7 +42,6 @@
|
||||
#ifdef HAVE_SYS_TYPES_H
|
||||
# include <sys/types.h>
|
||||
#endif
|
||||
#include <sys/time.h>
|
||||
#include <limits.h>
|
||||
#ifdef USE_TCP_FASTOPEN
|
||||
#include <netinet/tcp.h>
|
||||
@@ -1126,7 +1125,7 @@ make_sock_port(int stype, const char* ifname, int port,
|
||||
int use_systemd, int dscp, struct unbound_socket* ub_sock,
|
||||
const char* additional)
|
||||
{
|
||||
char* s = strchr(ifname, '@');
|
||||
const char* s = strchr(ifname, '@');
|
||||
if(s) {
|
||||
/* override port with ifspec@port */
|
||||
int port;
|
||||
@@ -1342,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) {
|
||||
@@ -1367,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);
|
||||
@@ -2134,7 +2151,7 @@ void listen_start_accept(struct listen_dnsport* listen)
|
||||
}
|
||||
|
||||
struct tcp_req_info*
|
||||
tcp_req_info_create(struct sldns_buffer* spoolbuf)
|
||||
tcp_req_info_create(struct comm_base* base, struct sldns_buffer* spoolbuf)
|
||||
{
|
||||
struct tcp_req_info* req = (struct tcp_req_info*)malloc(sizeof(*req));
|
||||
if(!req) {
|
||||
@@ -2142,6 +2159,12 @@ tcp_req_info_create(struct sldns_buffer* spoolbuf)
|
||||
return NULL;
|
||||
}
|
||||
memset(req, 0, sizeof(*req));
|
||||
req->read_again_timer = comm_timer_create(base, tcp_read_again_cb, req);
|
||||
if(!req->read_again_timer) {
|
||||
log_err("malloc failure");
|
||||
free(req);
|
||||
return NULL;
|
||||
}
|
||||
req->spool_buffer = spoolbuf;
|
||||
return req;
|
||||
}
|
||||
@@ -2151,6 +2174,7 @@ tcp_req_info_delete(struct tcp_req_info* req)
|
||||
{
|
||||
if(!req) return;
|
||||
tcp_req_info_clear(req);
|
||||
comm_timer_delete(req->read_again_timer);
|
||||
/* cp is pointer back to commpoint that owns this struct and
|
||||
* called delete on us */
|
||||
/* spool_buffer is shared udp buffer, not deleted here */
|
||||
@@ -2167,7 +2191,8 @@ void tcp_req_info_clear(struct tcp_req_info* req)
|
||||
open = req->open_req_list;
|
||||
while(open) {
|
||||
nopen = open->next;
|
||||
mesh_state_remove_reply(open->mesh, open->mesh_state, req->cp);
|
||||
mesh_state_remove_reply(open->mesh, open->mesh_state, req->cp,
|
||||
NULL, NULL);
|
||||
free(open);
|
||||
open = nopen;
|
||||
}
|
||||
@@ -2189,6 +2214,9 @@ void tcp_req_info_clear(struct tcp_req_info* req)
|
||||
req->done_req_list = NULL;
|
||||
req->num_done_req = 0;
|
||||
req->read_is_closed = 0;
|
||||
|
||||
if(comm_timer_is_set(req->read_again_timer))
|
||||
comm_timer_disable(req->read_again_timer);
|
||||
}
|
||||
|
||||
void
|
||||
@@ -3399,14 +3427,13 @@ doq_table_delete(struct doq_table* table)
|
||||
}
|
||||
|
||||
struct doq_timer*
|
||||
doq_timer_find_time(struct doq_table* table, struct timeval* tv)
|
||||
doq_timer_find_time(struct doq_table* table, ngtcp2_tstamp ts)
|
||||
{
|
||||
struct doq_timer key;
|
||||
struct rbnode_type* node;
|
||||
log_assert(table != NULL);
|
||||
memset(&key, 0, sizeof(key));
|
||||
key.time.tv_sec = tv->tv_sec;
|
||||
key.time.tv_usec = tv->tv_usec;
|
||||
key.time_mono = ts;
|
||||
node = rbtree_search(table->timer_tree, &key);
|
||||
if(node)
|
||||
return (struct doq_timer*)node->key;
|
||||
@@ -3454,7 +3481,7 @@ doq_timer_list_remove(struct doq_table* table, struct doq_timer* timer)
|
||||
if(!timer->timer_in_list)
|
||||
return;
|
||||
/* The item in the rbtree has the list start and end. */
|
||||
rb_timer = doq_timer_find_time(table, &timer->time);
|
||||
rb_timer = doq_timer_find_time(table, timer->time_mono);
|
||||
if(rb_timer) {
|
||||
if(timer->setlist_prev)
|
||||
timer->setlist_prev->setlist_next = timer->setlist_next;
|
||||
@@ -3500,7 +3527,8 @@ doq_timer_unset(struct doq_table* table, struct doq_timer* timer)
|
||||
}
|
||||
|
||||
void doq_timer_set(struct doq_table* table, struct doq_timer* timer,
|
||||
struct doq_server_socket* worker_doq_socket, struct timeval* tv)
|
||||
struct doq_server_socket* worker_doq_socket, struct timeval* tv,
|
||||
ngtcp2_tstamp ts)
|
||||
{
|
||||
struct doq_timer* rb_timer;
|
||||
if(verbosity >= VERB_ALGO && timer->conn) {
|
||||
@@ -3514,14 +3542,14 @@ void doq_timer_set(struct doq_table* table, struct doq_timer* timer,
|
||||
(int)rel.tv_sec, (int)rel.tv_usec);
|
||||
}
|
||||
if(timer->timer_in_tree || timer->timer_in_list) {
|
||||
if(timer->time.tv_sec == tv->tv_sec &&
|
||||
timer->time.tv_usec == tv->tv_usec)
|
||||
if(timer->time_mono == ts)
|
||||
return; /* already set on that time */
|
||||
doq_timer_unset(table, timer);
|
||||
}
|
||||
timer->time.tv_sec = tv->tv_sec;
|
||||
timer->time.tv_usec = tv->tv_usec;
|
||||
rb_timer = doq_timer_find_time(table, tv);
|
||||
timer->time_real.tv_sec = tv->tv_sec;
|
||||
timer->time_real.tv_usec = tv->tv_usec;
|
||||
timer->time_mono = ts;
|
||||
rb_timer = doq_timer_find_time(table, ts);
|
||||
if(rb_timer) {
|
||||
/* There is a timeout already with this value. Timer is
|
||||
* added to the setlist. */
|
||||
@@ -3597,15 +3625,29 @@ doq_conn_create(struct comm_point* c, struct doq_pkt_addr* paddr,
|
||||
return conn;
|
||||
}
|
||||
|
||||
/** The arguments for doq stream tree del. */
|
||||
struct doq_stream_tree_del_args {
|
||||
/** The doq table. */
|
||||
struct doq_table* table;
|
||||
/** The doq connection for the stream. */
|
||||
struct doq_conn* conn;
|
||||
};
|
||||
|
||||
/** delete stream tree node */
|
||||
static void
|
||||
stream_tree_del(rbnode_type* node, void* arg)
|
||||
{
|
||||
struct doq_table* table = (struct doq_table*)arg;
|
||||
struct doq_stream_tree_del_args* args = (struct doq_stream_tree_del_args*)arg;
|
||||
struct doq_table* table = args->table;
|
||||
struct doq_stream* stream;
|
||||
if(!node)
|
||||
return;
|
||||
stream = (struct doq_stream*)node;
|
||||
if(stream->mesh_state) {
|
||||
mesh_state_remove_reply(stream->mesh, stream->mesh_state,
|
||||
args->conn->doq_socket->cp, NULL, stream);
|
||||
stream->mesh_state = NULL;
|
||||
}
|
||||
if(stream->in)
|
||||
doq_table_quic_size_subtract(table, stream->inlen);
|
||||
if(stream->out)
|
||||
@@ -3625,9 +3667,14 @@ doq_conn_delete(struct doq_conn* conn, struct doq_table* table)
|
||||
lock_rw_unlock(&conn->table->conid_lock);
|
||||
/* Remove the app data from ngtcp2 before SSL_free of conn->ssl,
|
||||
* because the ngtcp2 conn is deleted. */
|
||||
SSL_set_app_data(conn->ssl, NULL);
|
||||
if(conn->ssl)
|
||||
SSL_set_app_data(conn->ssl, NULL);
|
||||
if(conn->stream_tree.count != 0) {
|
||||
traverse_postorder(&conn->stream_tree, stream_tree_del, table);
|
||||
struct doq_stream_tree_del_args args;
|
||||
memset(&args, 0, sizeof(args));
|
||||
args.table = table;
|
||||
args.conn = conn;
|
||||
traverse_postorder(&conn->stream_tree, stream_tree_del, &args);
|
||||
}
|
||||
free(conn->key.dcid);
|
||||
SSL_free(conn->ssl);
|
||||
@@ -3700,13 +3747,9 @@ int doq_timer_cmp(const void* key1, const void* key2)
|
||||
{
|
||||
struct doq_timer* e = (struct doq_timer*)key1;
|
||||
struct doq_timer* f = (struct doq_timer*)key2;
|
||||
if(e->time.tv_sec < f->time.tv_sec)
|
||||
if(e->time_mono < f->time_mono)
|
||||
return -1;
|
||||
if(e->time.tv_sec > f->time.tv_sec)
|
||||
return 1;
|
||||
if(e->time.tv_usec < f->time.tv_usec)
|
||||
return -1;
|
||||
if(e->time.tv_usec > f->time.tv_usec)
|
||||
if(e->time_mono > f->time_mono)
|
||||
return 1;
|
||||
return 0;
|
||||
}
|
||||
@@ -3940,6 +3983,11 @@ doq_stream_close(struct doq_conn* conn, struct doq_stream* stream,
|
||||
if(stream->is_closed)
|
||||
return 1;
|
||||
stream->is_closed = 1;
|
||||
if(stream->mesh_state) {
|
||||
mesh_state_remove_reply(stream->mesh, stream->mesh_state,
|
||||
conn->doq_socket->cp, NULL, stream);
|
||||
stream->mesh_state = NULL;
|
||||
}
|
||||
doq_stream_off_write_list(conn, stream);
|
||||
if(send_shutdown) {
|
||||
verbose(VERB_ALGO, "doq: shutdown stream_id %d with app_error_code %d",
|
||||
@@ -3969,7 +4017,8 @@ doq_stream_close(struct doq_conn* conn, struct doq_stream* stream,
|
||||
|
||||
/** doq stream pick up answer data from buffer */
|
||||
static int
|
||||
doq_stream_pickup_answer(struct doq_stream* stream, struct sldns_buffer* buf)
|
||||
doq_stream_pickup_answer(struct doq_conn* conn, struct doq_stream* stream,
|
||||
struct sldns_buffer* buf)
|
||||
{
|
||||
stream->is_answer_available = 1;
|
||||
if(stream->out) {
|
||||
@@ -3979,6 +4028,11 @@ doq_stream_pickup_answer(struct doq_stream* stream, struct sldns_buffer* buf)
|
||||
}
|
||||
stream->nwrite = 0;
|
||||
stream->outlen = sldns_buffer_limit(buf);
|
||||
if(!doq_table_quic_size_available(conn->doq_socket->table,
|
||||
conn->doq_socket->cfg, stream->outlen)) {
|
||||
verbose(VERB_ALGO, "doq stream: no space for reply length");
|
||||
return 0;
|
||||
}
|
||||
/* For quic the output bytes have to stay allocated and available,
|
||||
* for potential resends, until the remote end has acknowledged them.
|
||||
* This includes the tcplen start uint16_t, in outlen_wire. */
|
||||
@@ -4005,24 +4059,56 @@ doq_stream_send_reply(struct doq_conn* conn, struct doq_stream* stream,
|
||||
if(stream->out)
|
||||
doq_table_quic_size_subtract(conn->doq_socket->table,
|
||||
stream->outlen);
|
||||
if(!doq_stream_pickup_answer(stream, buf))
|
||||
if(!doq_stream_pickup_answer(conn, stream, buf))
|
||||
return 0;
|
||||
doq_table_quic_size_add(conn->doq_socket->table, stream->outlen);
|
||||
doq_stream_on_write_list(conn, stream);
|
||||
doq_conn_write_enable(conn);
|
||||
return 1;
|
||||
}
|
||||
#endif /* HAVE_NGTCP2 */
|
||||
|
||||
void
|
||||
doq_stream_add_meshstate(struct doq_stream* stream,
|
||||
struct mesh_area* mesh, struct mesh_state* m)
|
||||
{
|
||||
#ifdef HAVE_NGTCP2
|
||||
stream->mesh = mesh;
|
||||
stream->mesh_state = m;
|
||||
#else
|
||||
(void)stream; (void)mesh; (void)m;
|
||||
#endif
|
||||
}
|
||||
|
||||
void
|
||||
doq_stream_remove_mesh_state(struct doq_stream* stream)
|
||||
{
|
||||
#ifdef HAVE_NGTCP2
|
||||
if(!stream)
|
||||
return;
|
||||
stream->mesh_state = NULL;
|
||||
#else
|
||||
(void)stream;
|
||||
#endif
|
||||
}
|
||||
|
||||
#ifdef HAVE_NGTCP2
|
||||
/** doq stream data length has completed, allocations can be done. False on
|
||||
* allocation failure. */
|
||||
static int
|
||||
doq_stream_datalen_complete(struct doq_stream* stream, struct doq_table* table)
|
||||
doq_stream_datalen_complete(struct doq_conn* conn, struct doq_stream* stream,
|
||||
struct doq_table* table)
|
||||
{
|
||||
if(stream->inlen > 1024*1024) {
|
||||
log_err("doq stream in length too large %d",
|
||||
(int)stream->inlen);
|
||||
return 0;
|
||||
}
|
||||
if(!doq_table_quic_size_available(table, conn->doq_socket->cfg,
|
||||
stream->inlen)) {
|
||||
verbose(VERB_ALGO, "doq stream: no space for query length");
|
||||
return 0;
|
||||
}
|
||||
stream->in = calloc(1, stream->inlen);
|
||||
if(!stream->in) {
|
||||
log_err("doq could not read stream, calloc failed: "
|
||||
@@ -4067,6 +4153,7 @@ doq_stream_data_complete(struct doq_conn* conn, struct doq_stream* stream)
|
||||
return 0;
|
||||
}
|
||||
c->repinfo.doq_streamid = stream->stream_id;
|
||||
c->repinfo.doq_stream = stream;
|
||||
conn->doq_socket->current_conn = conn;
|
||||
fptr_ok(fptr_whitelist_comm_point(c->callback));
|
||||
if( (*c->callback)(c, c->cb_arg, NETEVENT_NOERROR, &c->repinfo)) {
|
||||
@@ -4083,8 +4170,9 @@ doq_stream_data_complete(struct doq_conn* conn, struct doq_stream* stream)
|
||||
|
||||
/** doq receive data for a stream, more bytes of the incoming data */
|
||||
static int
|
||||
doq_stream_recv_data(struct doq_stream* stream, const uint8_t* data,
|
||||
size_t datalen, int* recv_done, struct doq_table* table)
|
||||
doq_stream_recv_data(struct doq_conn* conn, struct doq_stream* stream,
|
||||
const uint8_t* data, size_t datalen, int* recv_done,
|
||||
struct doq_table* table)
|
||||
{
|
||||
int got_data = 0;
|
||||
/* read the tcplength uint16_t at the start */
|
||||
@@ -4105,7 +4193,7 @@ doq_stream_recv_data(struct doq_stream* stream, const uint8_t* data,
|
||||
if(stream->nread == 2) {
|
||||
/* the initial length value is completed */
|
||||
stream->inlen = ntohs(tcplen);
|
||||
if(!doq_stream_datalen_complete(stream, table))
|
||||
if(!doq_stream_datalen_complete(conn, stream, table))
|
||||
return 0;
|
||||
} else {
|
||||
/* store for later */
|
||||
@@ -4254,12 +4342,11 @@ doq_submit_new_token(struct doq_conn* conn)
|
||||
ngtcp2_ssize tokenlen;
|
||||
int ret;
|
||||
const ngtcp2_path* path = ngtcp2_conn_get_path(conn->conn);
|
||||
ngtcp2_tstamp ts = doq_get_timestamp_nanosec();
|
||||
|
||||
tokenlen = ngtcp2_crypto_generate_regular_token(token,
|
||||
conn->doq_socket->static_secret,
|
||||
conn->doq_socket->static_secret_len, path->remote.addr,
|
||||
path->remote.addrlen, ts);
|
||||
path->remote.addrlen, doq_get_timestamp_nanosec());
|
||||
if(tokenlen < 0) {
|
||||
log_err("doq ngtcp2_crypto_generate_regular_token failed");
|
||||
return 1;
|
||||
@@ -4322,8 +4409,7 @@ doq_stream_open_cb(ngtcp2_conn* ATTR_UNUSED(conn), int64_t stream_id,
|
||||
verbose(VERB_ALGO, "doq: stream with this id already exists");
|
||||
return 0;
|
||||
}
|
||||
if(stream_id != 0 && stream_id != 4 && /* allow one stream on a new connection */
|
||||
!doq_table_quic_size_available(doq_conn->doq_socket->table,
|
||||
if(!doq_table_quic_size_available(doq_conn->doq_socket->table,
|
||||
doq_conn->doq_socket->cfg, sizeof(*stream)
|
||||
+ 100 /* estimated query in */
|
||||
+ 512 /* estimated response out */
|
||||
@@ -4381,8 +4467,8 @@ doq_recv_stream_data_cb(ngtcp2_conn* ATTR_UNUSED(conn), uint32_t flags,
|
||||
return 0;
|
||||
}
|
||||
if(datalen != 0) {
|
||||
if(!doq_stream_recv_data(stream, data, datalen, &recv_done,
|
||||
doq_conn->doq_socket->table))
|
||||
if(!doq_stream_recv_data(doq_conn, stream, data, datalen,
|
||||
&recv_done, doq_conn->doq_socket->table))
|
||||
return NGTCP2_ERR_CALLBACK_FAILURE;
|
||||
}
|
||||
if((flags&NGTCP2_STREAM_DATA_FLAG_FIN)!=0) {
|
||||
@@ -4446,11 +4532,34 @@ doq_stream_reset_cb(ngtcp2_conn* ATTR_UNUSED(conn), int64_t stream_id,
|
||||
"unknown stream %d", (int)stream_id);
|
||||
return 0;
|
||||
}
|
||||
if(!doq_stream_close(doq_conn, stream, 0))
|
||||
if(!doq_stream_close(doq_conn, stream, 1))
|
||||
return NGTCP2_ERR_CALLBACK_FAILURE;
|
||||
return 0;
|
||||
}
|
||||
|
||||
/** ngtcp2 extend_max_stream_data function */
|
||||
int doq_extend_max_stream_data_cb(ngtcp2_conn* ATTR_UNUSED(conn),
|
||||
int64_t stream_id, uint64_t max_data, void* user_data,
|
||||
void* ATTR_UNUSED(stream_user_data))
|
||||
{
|
||||
struct doq_conn* doq_conn = (struct doq_conn*)user_data;
|
||||
struct doq_stream* stream;
|
||||
verbose(VERB_ALGO, "doq extend_max_stream_data stream id %d "
|
||||
"max_data %d ", (int)stream_id, (int)max_data);
|
||||
if(max_data == 0)
|
||||
return 0;
|
||||
stream = doq_stream_find(doq_conn, stream_id);
|
||||
if(!stream) {
|
||||
verbose(VERB_ALGO, "doq: unknown stream %d", (int)stream_id);
|
||||
return 0;
|
||||
}
|
||||
if(!stream->is_answer_available)
|
||||
return 0;
|
||||
doq_stream_on_write_list(doq_conn, stream);
|
||||
doq_conn_write_enable(doq_conn);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/** ngtcp2 acked_stream_data_offset callback function */
|
||||
static int
|
||||
doq_acked_stream_data_offset_cb(ngtcp2_conn* ATTR_UNUSED(conn),
|
||||
@@ -4771,7 +4880,7 @@ doq_ssl_server_setup(SSL_CTX* ctx, struct doq_conn* conn)
|
||||
SSL_set_app_data(ssl, conn);
|
||||
#endif
|
||||
SSL_set_accept_state(ssl);
|
||||
#ifdef USE_NGTCP2_CRYPTO_OSSL
|
||||
#ifdef HAVE_SSL_SET_QUIC_TLS_EARLY_DATA_ENABLED
|
||||
SSL_set_quic_tls_early_data_enabled(ssl, 1);
|
||||
#else
|
||||
SSL_set_quic_early_data_enabled(ssl, 1);
|
||||
@@ -4825,6 +4934,7 @@ doq_conn_setup(struct doq_conn* conn, uint8_t* scid, size_t scidlen,
|
||||
callbacks.stream_open = doq_stream_open_cb;
|
||||
callbacks.stream_close = doq_stream_close_cb;
|
||||
callbacks.stream_reset = doq_stream_reset_cb;
|
||||
callbacks.extend_max_stream_data = doq_extend_max_stream_data_cb;
|
||||
callbacks.acked_stream_data_offset = doq_acked_stream_data_offset_cb;
|
||||
callbacks.recv_stream_data = doq_recv_stream_data_cb;
|
||||
|
||||
@@ -4879,6 +4989,7 @@ doq_conn_setup(struct doq_conn* conn, uint8_t* scid, size_t scidlen,
|
||||
rv = ngtcp2_conn_server_new(&conn->conn, &scid_cid, &sv_scid, &path,
|
||||
conn->version, &callbacks, &settings, ¶ms, NULL, conn);
|
||||
if(rv != 0) {
|
||||
conn->conn = NULL;
|
||||
lock_rw_unlock(&conn->table->conid_lock);
|
||||
log_err("ngtcp2_conn_server_new failed: %s",
|
||||
ngtcp2_strerror(rv));
|
||||
@@ -5101,23 +5212,30 @@ doq_conn_clear_conids(struct doq_conn* conn)
|
||||
|
||||
ngtcp2_tstamp doq_get_timestamp_nanosec(void)
|
||||
{
|
||||
#ifdef CLOCK_REALTIME
|
||||
struct timespec tp;
|
||||
memset(&tp, 0, sizeof(tp));
|
||||
/* Get a nanosecond time, that can be compared with the event base. */
|
||||
if(clock_gettime(CLOCK_REALTIME, &tp) == -1) {
|
||||
log_err("clock_gettime failed: %s", strerror(errno));
|
||||
#ifdef CLOCK_BOOTTIME
|
||||
if(clock_gettime(CLOCK_BOOTTIME, &tp) == -1) {
|
||||
#endif
|
||||
if(clock_gettime(CLOCK_MONOTONIC, &tp) == -1) {
|
||||
log_err("clock_gettime failed: %s", strerror(errno));
|
||||
}
|
||||
#ifdef CLOCK_BOOTTIME
|
||||
}
|
||||
#endif
|
||||
return ((uint64_t)tp.tv_sec)*((uint64_t)1000000000) +
|
||||
((uint64_t)tp.tv_nsec);
|
||||
#else
|
||||
}
|
||||
|
||||
static struct timeval doq_get_timevalue(void)
|
||||
{
|
||||
struct timeval tv;
|
||||
memset(&tv, 0, sizeof(tv));
|
||||
if(gettimeofday(&tv, NULL) < 0) {
|
||||
log_err("gettimeofday failed: %s", strerror(errno));
|
||||
memset(&tv, 0, sizeof(tv));
|
||||
}
|
||||
return ((uint64_t)tv.tv_sec)*((uint64_t)1000000000) +
|
||||
((uint64_t)tv.tv_usec)*((uint64_t)1000);
|
||||
#endif /* CLOCK_REALTIME */
|
||||
return tv;
|
||||
}
|
||||
|
||||
/** doq start the closing period for the connection. */
|
||||
@@ -5240,18 +5358,17 @@ doq_conn_recv(struct comm_point* c, struct doq_pkt_addr* paddr,
|
||||
int* err_drop)
|
||||
{
|
||||
int ret;
|
||||
ngtcp2_tstamp ts;
|
||||
struct ngtcp2_path path;
|
||||
memset(&path, 0, sizeof(path));
|
||||
path.remote.addr = (struct sockaddr*)&paddr->addr;
|
||||
path.remote.addrlen = paddr->addrlen;
|
||||
path.local.addr = (struct sockaddr*)&paddr->localaddr;
|
||||
path.local.addrlen = paddr->localaddrlen;
|
||||
ts = doq_get_timestamp_nanosec();
|
||||
|
||||
ret = ngtcp2_conn_read_pkt(conn->conn, &path, pi,
|
||||
sldns_buffer_begin(c->doq_socket->pkt_buf),
|
||||
sldns_buffer_limit(c->doq_socket->pkt_buf), ts);
|
||||
sldns_buffer_limit(c->doq_socket->pkt_buf),
|
||||
doq_get_timestamp_nanosec());
|
||||
if(ret != 0) {
|
||||
if(err_retry)
|
||||
*err_retry = 0;
|
||||
@@ -5339,7 +5456,6 @@ doq_conn_write_streams(struct comm_point* c, struct doq_conn* conn,
|
||||
{
|
||||
struct doq_stream* stream = conn->stream_write_first;
|
||||
ngtcp2_path_storage ps;
|
||||
ngtcp2_tstamp ts = doq_get_timestamp_nanosec();
|
||||
size_t num_packets = 0, max_packets = 65535;
|
||||
ngtcp2_path_storage_zero(&ps);
|
||||
|
||||
@@ -5392,7 +5508,8 @@ doq_conn_write_streams(struct comm_point* c, struct doq_conn* conn,
|
||||
ret = ngtcp2_conn_writev_stream(conn->conn, &ps.path, &pi,
|
||||
sldns_buffer_begin(c->doq_socket->pkt_buf),
|
||||
sldns_buffer_remaining(c->doq_socket->pkt_buf),
|
||||
&ndatalen, flags, stream_id, datav, datav_count, ts);
|
||||
&ndatalen, flags, stream_id, datav, datav_count,
|
||||
doq_get_timestamp_nanosec());
|
||||
if(ret < 0) {
|
||||
if(ret == NGTCP2_ERR_WRITE_MORE) {
|
||||
verbose(VERB_ALGO, "doq: write more, ndatalen %d", (int)ndatalen);
|
||||
@@ -5407,26 +5524,20 @@ doq_conn_write_streams(struct comm_point* c, struct doq_conn* conn,
|
||||
continue;
|
||||
} else if(ret == NGTCP2_ERR_STREAM_DATA_BLOCKED) {
|
||||
verbose(VERB_ALGO, "doq: ngtcp2_conn_writev_stream returned NGTCP2_ERR_STREAM_DATA_BLOCKED");
|
||||
#ifdef HAVE_NGTCP2_CCERR_DEFAULT
|
||||
ngtcp2_ccerr_set_application_error(
|
||||
&conn->ccerr, -1, NULL, 0);
|
||||
#else
|
||||
ngtcp2_connection_close_error_set_application_error(&conn->last_error, -1, NULL, 0);
|
||||
#endif
|
||||
if(err_drop)
|
||||
*err_drop = 0;
|
||||
if(!doq_conn_close_error(c, conn)) {
|
||||
if(err_drop)
|
||||
*err_drop = 1;
|
||||
if(stream) {
|
||||
doq_stream_off_write_list(conn, stream);
|
||||
stream = stream->write_next;
|
||||
continue;
|
||||
} else {
|
||||
break;
|
||||
}
|
||||
return 0;
|
||||
} else if(ret == NGTCP2_ERR_STREAM_SHUT_WR) {
|
||||
verbose(VERB_ALGO, "doq: ngtcp2_conn_writev_stream returned NGTCP2_ERR_STREAM_SHUT_WR");
|
||||
#ifdef HAVE_NGTCP2_CCERR_DEFAULT
|
||||
ngtcp2_ccerr_set_application_error(
|
||||
&conn->ccerr, -1, NULL, 0);
|
||||
&conn->ccerr, DOQ_APP_ERROR_CODE, NULL, 0);
|
||||
#else
|
||||
ngtcp2_connection_close_error_set_application_error(&conn->last_error, -1, NULL, 0);
|
||||
ngtcp2_connection_close_error_set_application_error(&conn->last_error, DOQ_APP_ERROR_CODE, NULL, 0);
|
||||
#endif
|
||||
if(err_drop)
|
||||
*err_drop = 0;
|
||||
@@ -5464,7 +5575,8 @@ doq_conn_write_streams(struct comm_point* c, struct doq_conn* conn,
|
||||
if(ret == 0) {
|
||||
/* congestion limited */
|
||||
doq_conn_write_disable(conn);
|
||||
ngtcp2_conn_update_pkt_tx_time(conn->conn, ts);
|
||||
ngtcp2_conn_update_pkt_tx_time(conn->conn,
|
||||
doq_get_timestamp_nanosec());
|
||||
return 1;
|
||||
}
|
||||
sldns_buffer_set_position(c->doq_socket->pkt_buf, ret);
|
||||
@@ -5478,7 +5590,7 @@ doq_conn_write_streams(struct comm_point* c, struct doq_conn* conn,
|
||||
if(stream)
|
||||
stream = stream->write_next;
|
||||
}
|
||||
ngtcp2_conn_update_pkt_tx_time(conn->conn, ts);
|
||||
ngtcp2_conn_update_pkt_tx_time(conn->conn, doq_get_timestamp_nanosec());
|
||||
return 1;
|
||||
}
|
||||
|
||||
@@ -5555,32 +5667,35 @@ doq_table_pop_first(struct doq_table* table)
|
||||
}
|
||||
|
||||
int
|
||||
doq_conn_check_timer(struct doq_conn* conn, struct timeval* tv)
|
||||
doq_conn_check_timer(struct doq_conn* conn, struct timeval* tv, ngtcp2_tstamp* ts)
|
||||
{
|
||||
ngtcp2_tstamp expiry = ngtcp2_conn_get_expiry(conn->conn);
|
||||
ngtcp2_tstamp now = doq_get_timestamp_nanosec();
|
||||
ngtcp2_tstamp doq_expiry = ngtcp2_conn_get_expiry(conn->conn);
|
||||
ngtcp2_tstamp doq_now = doq_get_timestamp_nanosec();
|
||||
ngtcp2_tstamp t;
|
||||
struct timeval now = doq_get_timevalue();
|
||||
|
||||
if(expiry <= now) {
|
||||
if(doq_expiry <= doq_now || doq_expiry == UINT64_MAX) {
|
||||
/* UINT64_MAX means there is no next expiry. */
|
||||
/* The timer has already expired, add with zero timeout.
|
||||
* This should call the callback straight away. Calling it
|
||||
* from the event callbacks is cleaner than calling it here,
|
||||
* because then it is always called with the same locks and
|
||||
* so on. This routine only has the conn.lock. */
|
||||
t = now;
|
||||
t = doq_now;
|
||||
memcpy(tv, &now, sizeof(*tv));
|
||||
} else {
|
||||
t = expiry;
|
||||
t = doq_expiry;
|
||||
memset(tv, 0, sizeof(*tv));
|
||||
tv->tv_sec = (doq_expiry - doq_now) / NGTCP2_SECONDS;
|
||||
tv->tv_usec = ((doq_expiry - doq_now) / NGTCP2_MICROSECONDS)%1000000;
|
||||
timeval_add(tv, &now);
|
||||
}
|
||||
|
||||
/* convert to timeval */
|
||||
memset(tv, 0, sizeof(*tv));
|
||||
tv->tv_sec = t / NGTCP2_SECONDS;
|
||||
tv->tv_usec = (t / NGTCP2_MICROSECONDS)%1000000;
|
||||
*ts = t;
|
||||
|
||||
/* If we already have a timer, is it the right value? */
|
||||
if(conn->timer.timer_in_tree || conn->timer.timer_in_list) {
|
||||
if(conn->timer.time.tv_sec == tv->tv_sec &&
|
||||
conn->timer.time.tv_usec == tv->tv_usec)
|
||||
if(conn->timer.time_mono == *ts)
|
||||
return 0;
|
||||
}
|
||||
return 1;
|
||||
@@ -5601,13 +5716,12 @@ doq_conn_log_line(struct doq_conn* conn, char* s)
|
||||
int
|
||||
doq_conn_handle_timeout(struct doq_conn* conn)
|
||||
{
|
||||
ngtcp2_tstamp now = doq_get_timestamp_nanosec();
|
||||
int rv;
|
||||
|
||||
if(verbosity >= VERB_ALGO)
|
||||
doq_conn_log_line(conn, "timeout");
|
||||
|
||||
rv = ngtcp2_conn_handle_expiry(conn->conn, now);
|
||||
rv = ngtcp2_conn_handle_expiry(conn->conn, doq_get_timestamp_nanosec());
|
||||
if(rv != 0) {
|
||||
verbose(VERB_ALGO, "ngtcp2_conn_handle_expiry failed: %s",
|
||||
ngtcp2_strerror(rv));
|
||||
|
||||
@@ -61,6 +61,8 @@ struct config_file;
|
||||
struct addrinfo;
|
||||
struct sldns_buffer;
|
||||
struct tcl_list;
|
||||
struct mesh_area;
|
||||
struct mesh_state;
|
||||
|
||||
/**
|
||||
* Listening for queries structure.
|
||||
@@ -345,6 +347,10 @@ struct tcp_req_info {
|
||||
int num_done_req;
|
||||
/** list of pending writable result packets, malloced one at a time */
|
||||
struct tcp_req_done_item* done_req_list;
|
||||
/** the read again timer, when the number of pipelined TCP queries
|
||||
* is large, it waits, zero time, for a new event loop to service
|
||||
* the remainder of the TCP traffic on the fd. */
|
||||
struct comm_timer* read_again_timer;
|
||||
};
|
||||
|
||||
/**
|
||||
@@ -375,10 +381,12 @@ struct tcp_req_done_item {
|
||||
* Create tcp request info structure that keeps track of open
|
||||
* requests on the TCP channel that are resolved at the same time,
|
||||
* and the pending results that have to get written back to that client.
|
||||
* @param base: comm base for read again timer.
|
||||
* @param spoolbuf: shared buffer
|
||||
* @return new structure or NULL on alloc failure.
|
||||
*/
|
||||
struct tcp_req_info* tcp_req_info_create(struct sldns_buffer* spoolbuf);
|
||||
struct tcp_req_info* tcp_req_info_create(struct comm_base* base,
|
||||
struct sldns_buffer* spoolbuf);
|
||||
|
||||
/**
|
||||
* Delete tcp request structure. Called by owning commpoint.
|
||||
@@ -538,8 +546,11 @@ void doq_table_delete(struct doq_table* table);
|
||||
struct doq_timer {
|
||||
/** The rbnode in the tree sorted by timeout value. Key this struct. */
|
||||
struct rbnode_type node;
|
||||
/** The timeout value. Monotonic value used with ngtcp2.
|
||||
* This time value is used for the tree operations. */
|
||||
ngtcp2_tstamp time_mono;
|
||||
/** The timeout value. Absolute time value. */
|
||||
struct timeval time;
|
||||
struct timeval time_real;
|
||||
/** If the timer is in the time tree, with the node. */
|
||||
int timer_in_tree;
|
||||
/** If there are more timers with the exact same timeout value,
|
||||
@@ -689,6 +700,11 @@ struct doq_stream {
|
||||
uint8_t* out;
|
||||
/** if the stream is on the write list */
|
||||
uint8_t on_write_list;
|
||||
/** The mesh area and mesh state, set when this stream's query was
|
||||
* dispatched into the mesh; used to detach the reply on stream close */
|
||||
struct mesh_area* mesh;
|
||||
/** the mesh state for the query, is nonNULL when there is one. */
|
||||
struct mesh_state* mesh_state;
|
||||
/** the prev and next on the write list, if on the list */
|
||||
struct doq_stream* write_prev, *write_next;
|
||||
};
|
||||
@@ -791,7 +807,16 @@ int doq_stream_close(struct doq_conn* conn, struct doq_stream* stream,
|
||||
/** send reply for a connection */
|
||||
int doq_stream_send_reply(struct doq_conn* conn, struct doq_stream* stream,
|
||||
struct sldns_buffer* buf);
|
||||
#endif /* HAVE_NGTCP2 */
|
||||
|
||||
/** add mesh state to doq stream */
|
||||
void doq_stream_add_meshstate(struct doq_stream* stream,
|
||||
struct mesh_area* mesh, struct mesh_state* m);
|
||||
|
||||
/** remove mesh state from doq stream */
|
||||
void doq_stream_remove_mesh_state(struct doq_stream* stream);
|
||||
|
||||
#ifdef HAVE_NGTCP2
|
||||
/** the connection has write interest, wants to write packets */
|
||||
void doq_conn_write_enable(struct doq_conn* conn);
|
||||
|
||||
@@ -813,10 +838,12 @@ struct doq_conn* doq_table_pop_first(struct doq_table* table);
|
||||
* doq check if the timer for the conn needs to be changed.
|
||||
* @param conn: connection, caller must hold lock on it.
|
||||
* @param tv: time value, absolute time, returned.
|
||||
* @param ts: time stamp, absolute time, returned.
|
||||
* @return true if timer needs to be set to tv, false if no change is needed
|
||||
* to the timer. The timer is already set to the right time in that case.
|
||||
*/
|
||||
int doq_conn_check_timer(struct doq_conn* conn, struct timeval* tv);
|
||||
int doq_conn_check_timer(struct doq_conn* conn, struct timeval* tv,
|
||||
ngtcp2_tstamp* ts);
|
||||
|
||||
/** doq remove timer from tree */
|
||||
void doq_timer_tree_remove(struct doq_table* table, struct doq_timer* timer);
|
||||
@@ -829,11 +856,12 @@ void doq_timer_unset(struct doq_table* table, struct doq_timer* timer);
|
||||
|
||||
/** doq set the timer and add it. */
|
||||
void doq_timer_set(struct doq_table* table, struct doq_timer* timer,
|
||||
struct doq_server_socket* worker_doq_socket, struct timeval* tv);
|
||||
struct doq_server_socket* worker_doq_socket, struct timeval* tv,
|
||||
ngtcp2_tstamp ts);
|
||||
|
||||
/** doq find a timeout in the timer tree */
|
||||
struct doq_timer* doq_timer_find_time(struct doq_table* table,
|
||||
struct timeval* tv);
|
||||
ngtcp2_tstamp ts);
|
||||
|
||||
/** doq handle timeout for a connection. Pass conn locked. Returns false for
|
||||
* deletion. */
|
||||
@@ -851,6 +879,9 @@ int doq_table_quic_size_available(struct doq_table* table,
|
||||
|
||||
/** doq get the quic size value */
|
||||
size_t doq_table_quic_size_get(struct doq_table* table);
|
||||
|
||||
/** get a timestamp in nanoseconds */
|
||||
ngtcp2_tstamp doq_get_timestamp_nanosec(void);
|
||||
#endif /* HAVE_NGTCP2 */
|
||||
|
||||
char* set_ip_dscp(int socket, int addrfamily, int ds);
|
||||
@@ -866,8 +897,4 @@ void doq_client_event_cb(int fd, short event, void* arg);
|
||||
/** timer event callback for testcode/doqclient */
|
||||
void doq_client_timer_cb(int fd, short event, void* arg);
|
||||
|
||||
#ifdef HAVE_NGTCP2
|
||||
/** get a timestamp in nanoseconds */
|
||||
ngtcp2_tstamp doq_get_timestamp_nanosec(void);
|
||||
#endif
|
||||
#endif /* LISTEN_DNSPORT_H */
|
||||
|
||||
+56
-11
@@ -386,8 +386,6 @@ new_local_rrset(struct regional* region, struct local_data* node,
|
||||
log_err("out of memory");
|
||||
return NULL;
|
||||
}
|
||||
rrset->next = node->rrsets;
|
||||
node->rrsets = rrset;
|
||||
rrset->rrset = (struct ub_packed_rrset_key*)
|
||||
regional_alloc_zero(region, sizeof(*rrset->rrset));
|
||||
if(!rrset->rrset) {
|
||||
@@ -408,6 +406,8 @@ new_local_rrset(struct regional* region, struct local_data* node,
|
||||
rrset->rrset->rk.dname_len = node->namelen;
|
||||
rrset->rrset->rk.type = htons(rrtype);
|
||||
rrset->rrset->rk.rrset_class = htons(rrclass);
|
||||
rrset->next = node->rrsets;
|
||||
node->rrsets = rrset;
|
||||
return rrset;
|
||||
}
|
||||
|
||||
@@ -431,6 +431,10 @@ rrset_insert_rr(struct regional* region, struct packed_rrset_data* pd,
|
||||
pd->rr_ttl = regional_alloc(region, sizeof(*pd->rr_ttl)*pd->count);
|
||||
pd->rr_data = regional_alloc(region, sizeof(*pd->rr_data)*pd->count);
|
||||
if(!pd->rr_len || !pd->rr_ttl || !pd->rr_data) {
|
||||
pd->count--;
|
||||
pd->rr_len = oldlen;
|
||||
pd->rr_ttl = oldttl;
|
||||
pd->rr_data = olddata;
|
||||
log_err("out of memory");
|
||||
return 0;
|
||||
}
|
||||
@@ -446,6 +450,10 @@ rrset_insert_rr(struct regional* region, struct packed_rrset_data* pd,
|
||||
pd->rr_ttl[0] = ttl;
|
||||
pd->rr_data[0] = regional_alloc_init(region, rdata, rdata_len);
|
||||
if(!pd->rr_data[0]) {
|
||||
pd->count--;
|
||||
pd->rr_len = oldlen;
|
||||
pd->rr_ttl = oldttl;
|
||||
pd->rr_data = olddata;
|
||||
log_err("out of memory");
|
||||
return 0;
|
||||
}
|
||||
@@ -671,7 +679,9 @@ lz_enter_rr_str(struct local_zones* zones, const char* rr)
|
||||
z = local_zones_lookup(zones, rr_name, len, labs, rr_class, rr_type, 1);
|
||||
if(!z) {
|
||||
lock_rw_unlock(&zones->lock);
|
||||
fatal_exit("internal error: no zone for rr %s", rr);
|
||||
log_err("internal error: no zone for rr %s", rr);
|
||||
free(rr_name);
|
||||
return 0;
|
||||
}
|
||||
lock_rw_wrlock(&z->lock);
|
||||
lock_rw_unlock(&zones->lock);
|
||||
@@ -1500,8 +1510,10 @@ find_tag_datas(struct query_info* qinfo, struct config_strlist* list,
|
||||
return 0; /* out of memory */
|
||||
qinfo->local_alias->rrset =
|
||||
regional_alloc_init(temp, r, sizeof(*r));
|
||||
if(!qinfo->local_alias->rrset)
|
||||
if(!qinfo->local_alias->rrset) {
|
||||
qinfo->local_alias = NULL;
|
||||
return 0; /* out of memory */
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
@@ -1567,13 +1579,17 @@ local_data_answer(struct local_zone* z, struct module_env* env,
|
||||
return 0; /* out of memory */
|
||||
qinfo->local_alias->rrset = regional_alloc_init(
|
||||
temp, lr->rrset, sizeof(*lr->rrset));
|
||||
if(!qinfo->local_alias->rrset)
|
||||
if(!qinfo->local_alias->rrset) {
|
||||
qinfo->local_alias = NULL;
|
||||
return 0; /* out of memory */
|
||||
}
|
||||
qinfo->local_alias->rrset->rk.dname = qinfo->qname;
|
||||
qinfo->local_alias->rrset->rk.dname_len = qinfo->qname_len;
|
||||
get_cname_target(lr->rrset, &ctarget, &ctargetlen);
|
||||
if(!ctargetlen)
|
||||
if(!ctargetlen) {
|
||||
qinfo->local_alias = NULL;
|
||||
return 0; /* invalid cname */
|
||||
}
|
||||
if(dname_is_wild(ctarget)) {
|
||||
/* synthesize cname target */
|
||||
struct packed_rrset_data* d, *lr_d;
|
||||
@@ -1602,8 +1618,10 @@ local_data_answer(struct local_zone* z, struct module_env* env,
|
||||
sizeof(struct packed_rrset_data) + sizeof(size_t) +
|
||||
sizeof(uint8_t*) + sizeof(time_t) + sizeof(uint16_t)
|
||||
+ newtargetlen);
|
||||
if(!d)
|
||||
if(!d) {
|
||||
qinfo->local_alias = NULL;
|
||||
return 0; /* out of memory */
|
||||
}
|
||||
lr_d = (struct packed_rrset_data*)lr->rrset->entry.data;
|
||||
qinfo->local_alias->rrset->entry.data = d;
|
||||
d->ttl = lr_d->rr_ttl[0]; /* RFC6672-like behavior:
|
||||
@@ -1650,7 +1668,7 @@ local_zone_does_not_cover(struct local_zone* z, struct query_info* qinfo,
|
||||
struct local_data key;
|
||||
struct local_data* ld = NULL;
|
||||
struct local_rrset* lr = NULL;
|
||||
if(z->type == local_zone_always_transparent || z->type == local_zone_block_a)
|
||||
if(z->type == local_zone_always_transparent || z->type == local_zone_block_a || z->type == local_zone_block_aaaa)
|
||||
return 1;
|
||||
if(z->type != local_zone_transparent
|
||||
&& z->type != local_zone_typetransparent
|
||||
@@ -1661,7 +1679,9 @@ local_zone_does_not_cover(struct local_zone* z, struct query_info* qinfo,
|
||||
key.namelen = qinfo->qname_len;
|
||||
key.namelabs = labs;
|
||||
ld = (struct local_data*)rbtree_search(&z->data, &key.node);
|
||||
if(z->type == local_zone_transparent || z->type == local_zone_inform)
|
||||
if(z->type == local_zone_transparent || z->type == local_zone_inform
|
||||
|| z->type == local_zone_block_a_wdata
|
||||
|| z->type == local_zone_block_aaaa_wdata)
|
||||
return (ld == NULL);
|
||||
if(ld)
|
||||
lr = local_data_find_type(ld, qinfo->qtype, 1);
|
||||
@@ -1727,7 +1747,8 @@ local_zones_zone_answer(struct local_zone* z, struct module_env* env,
|
||||
|| lz_type == local_zone_always_transparent) {
|
||||
/* no NODATA or NXDOMAINS for this zone type */
|
||||
return 0;
|
||||
} else if(lz_type == local_zone_block_a) {
|
||||
} else if(lz_type == local_zone_block_a ||
|
||||
lz_type == local_zone_block_a_wdata) {
|
||||
/* Return NODATA for all A queries */
|
||||
if(qinfo->qtype == LDNS_RR_TYPE_A) {
|
||||
local_error_encode(qinfo, env, edns, repinfo, buf, temp,
|
||||
@@ -1736,6 +1757,17 @@ local_zones_zone_answer(struct local_zone* z, struct module_env* env,
|
||||
return 1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
} else if(lz_type == local_zone_block_aaaa ||
|
||||
lz_type == local_zone_block_aaaa_wdata) {
|
||||
/* Return NODATA for all AAAA queries */
|
||||
if(qinfo->qtype == LDNS_RR_TYPE_AAAA) {
|
||||
local_error_encode(qinfo, env, edns, repinfo, buf, temp,
|
||||
LDNS_RCODE_NOERROR, (LDNS_RCODE_NOERROR|BIT_AA),
|
||||
LDNS_EDE_NONE, NULL);
|
||||
return 1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
} else if(lz_type == local_zone_always_null) {
|
||||
/* 0.0.0.0 or ::0 or noerror/nodata for this zone type,
|
||||
@@ -1904,7 +1936,10 @@ local_zones_answer(struct local_zones* zones, struct module_env* env,
|
||||
lzt == local_zone_typetransparent ||
|
||||
lzt == local_zone_inform ||
|
||||
lzt == local_zone_always_transparent ||
|
||||
lzt == local_zone_block_a) &&
|
||||
lzt == local_zone_block_a ||
|
||||
lzt == local_zone_block_aaaa ||
|
||||
lzt == local_zone_block_a_wdata ||
|
||||
lzt == local_zone_block_aaaa_wdata) &&
|
||||
local_zone_does_not_cover(z, qinfo, labs)) {
|
||||
lock_rw_unlock(&z->lock);
|
||||
z = NULL;
|
||||
@@ -1953,6 +1988,7 @@ local_zones_answer(struct local_zones* zones, struct module_env* env,
|
||||
if(lzt != local_zone_always_refuse
|
||||
&& lzt != local_zone_always_transparent
|
||||
&& lzt != local_zone_block_a
|
||||
&& lzt != local_zone_block_aaaa
|
||||
&& lzt != local_zone_always_nxdomain
|
||||
&& lzt != local_zone_always_nodata
|
||||
&& lzt != local_zone_always_deny
|
||||
@@ -1984,6 +2020,9 @@ const char* local_zone_type2str(enum localzone_type t)
|
||||
case local_zone_inform_redirect: return "inform_redirect";
|
||||
case local_zone_always_transparent: return "always_transparent";
|
||||
case local_zone_block_a: return "block_a";
|
||||
case local_zone_block_aaaa: return "block_aaaa";
|
||||
case local_zone_block_a_wdata: return "block_a_wdata";
|
||||
case local_zone_block_aaaa_wdata: return "block_aaaa_wdata";
|
||||
case local_zone_always_refuse: return "always_refuse";
|
||||
case local_zone_always_nxdomain: return "always_nxdomain";
|
||||
case local_zone_always_nodata: return "always_nodata";
|
||||
@@ -2020,6 +2059,12 @@ int local_zone_str2type(const char* type, enum localzone_type* t)
|
||||
*t = local_zone_always_transparent;
|
||||
else if(strcmp(type, "block_a") == 0)
|
||||
*t = local_zone_block_a;
|
||||
else if(strcmp(type, "block_aaaa") == 0)
|
||||
*t = local_zone_block_aaaa;
|
||||
else if(strcmp(type, "block_a_wdata") == 0)
|
||||
*t = local_zone_block_a_wdata;
|
||||
else if(strcmp(type, "block_aaaa_wdata") == 0)
|
||||
*t = local_zone_block_aaaa_wdata;
|
||||
else if(strcmp(type, "always_refuse") == 0)
|
||||
*t = local_zone_always_refuse;
|
||||
else if(strcmp(type, "always_nxdomain") == 0)
|
||||
|
||||
@@ -93,6 +93,12 @@ enum localzone_type {
|
||||
local_zone_always_transparent,
|
||||
/** resolve normally, even when there is local data but return NODATA for A queries */
|
||||
local_zone_block_a,
|
||||
/** resolve normally, even when there is local data, but return NODATA for AAAA queries */
|
||||
local_zone_block_aaaa,
|
||||
/** resolve normally, use local data, else return NODATA for A queries */
|
||||
local_zone_block_a_wdata,
|
||||
/** resolve normally, use local data, else return NODATA for AAAA queries */
|
||||
local_zone_block_aaaa_wdata,
|
||||
/** answer with error, even when there is local data */
|
||||
local_zone_always_refuse,
|
||||
/** answer with nxdomain, even when there is local data */
|
||||
@@ -573,7 +579,7 @@ enum respip_action {
|
||||
respip_always_nxdomain = local_zone_always_nxdomain,
|
||||
/** answer with nodata response */
|
||||
respip_always_nodata = local_zone_always_nodata,
|
||||
/** answer with nodata response */
|
||||
/** drop query */
|
||||
respip_always_deny = local_zone_always_deny,
|
||||
/** RPZ: truncate answer in order to force switch to tcp */
|
||||
respip_truncate = local_zone_truncate,
|
||||
|
||||
+261
-144
@@ -373,7 +373,7 @@ mesh_serve_expired_lookup(struct module_qstate* qstate,
|
||||
"validation");
|
||||
goto bail_out; /* need to validate cache entry first */
|
||||
} else if(msg->rep->security == sec_status_secure &&
|
||||
!reply_all_rrsets_secure(msg->rep) && must_validate) {
|
||||
!reply_an_ns_rrsets_secure(msg->rep) && must_validate) {
|
||||
verbose(VERB_ALGO, "Serve expired: secure entry"
|
||||
" changed status");
|
||||
goto bail_out; /* rrset changed, re-verify */
|
||||
@@ -424,6 +424,44 @@ mesh_serve_expired_init(struct mesh_state* mstate, int timeout)
|
||||
return 1;
|
||||
}
|
||||
|
||||
/** remove a reply without accounting, rollback the add reply. */
|
||||
static void
|
||||
mesh_remove_reply_without_accounting(struct mesh_state* s,
|
||||
struct mesh_reply* todel)
|
||||
{
|
||||
struct mesh_reply* r, *prev = NULL;
|
||||
for(r = s->reply_list; r; r = r->next) {
|
||||
if(r == todel) {
|
||||
if(prev)
|
||||
prev->next = r->next;
|
||||
else s->reply_list = r->next;
|
||||
r->next = NULL;
|
||||
/* todel is allocated in region */
|
||||
return;
|
||||
}
|
||||
prev = r;
|
||||
}
|
||||
}
|
||||
|
||||
/** remove a callback without accounting, rollback the add reply. */
|
||||
static void
|
||||
mesh_remove_callback_without_accounting(struct mesh_state* s,
|
||||
struct mesh_cb* todel)
|
||||
{
|
||||
struct mesh_cb* r, *prev = NULL;
|
||||
for(r = s->cb_list; r; r = r->next) {
|
||||
if(r == todel) {
|
||||
if(prev)
|
||||
prev->next = r->next;
|
||||
else s->cb_list = r->next;
|
||||
r->next = NULL;
|
||||
/* todel is allocated in region */
|
||||
return;
|
||||
}
|
||||
prev = r;
|
||||
}
|
||||
}
|
||||
|
||||
void mesh_new_client(struct mesh_area* mesh, struct query_info* qinfo,
|
||||
struct respip_client_info* cinfo, uint16_t qflags,
|
||||
struct edns_data* edns, struct comm_reply* rep, uint16_t qid,
|
||||
@@ -433,7 +471,8 @@ void mesh_new_client(struct mesh_area* mesh, struct query_info* qinfo,
|
||||
int unique = unique_mesh_state(edns->opt_list_in, mesh->env);
|
||||
int was_detached = 0;
|
||||
int was_noreply = 0;
|
||||
int added = 0;
|
||||
int added = 0, added_reply_without_accounting = 0, added_tcp = 0;
|
||||
struct mesh_reply* repadded = NULL;
|
||||
int timeout = mesh->env->cfg->serve_expired?
|
||||
mesh->env->cfg->serve_expired_client_timeout:0;
|
||||
struct sldns_buffer* r_buffer = rep->c->buffer;
|
||||
@@ -467,6 +506,8 @@ void mesh_new_client(struct mesh_area* mesh, struct query_info* qinfo,
|
||||
"incoming query.");
|
||||
if(rep->c->use_h2)
|
||||
http2_stream_remove_mesh_state(rep->c->h2_stream);
|
||||
else if(rep->c->type == comm_doq && rep->doq_stream)
|
||||
doq_stream_remove_mesh_state(rep->doq_stream);
|
||||
comm_point_drop_reply(rep);
|
||||
mesh->stats_dropped++;
|
||||
return;
|
||||
@@ -480,6 +521,8 @@ void mesh_new_client(struct mesh_area* mesh, struct query_info* qinfo,
|
||||
"dropping incoming query.");
|
||||
if(rep->c->use_h2)
|
||||
http2_stream_remove_mesh_state(rep->c->h2_stream);
|
||||
else if(rep->c->type == comm_doq && rep->doq_stream)
|
||||
doq_stream_remove_mesh_state(rep->doq_stream);
|
||||
comm_point_drop_reply(rep);
|
||||
mesh->num_queries_replyaddr_limit++;
|
||||
return;
|
||||
@@ -540,18 +583,22 @@ void mesh_new_client(struct mesh_area* mesh, struct query_info* qinfo,
|
||||
}
|
||||
}
|
||||
/* add reply to s */
|
||||
if(!mesh_state_add_reply(s, edns, rep, qid, qflags, qinfo)) {
|
||||
if(!mesh_state_add_reply(s, edns, rep, qid, qflags, qinfo, &repadded)) {
|
||||
log_err("mesh_new_client: out of memory; SERVFAIL");
|
||||
goto servfail_mem;
|
||||
}
|
||||
added_reply_without_accounting = 1;
|
||||
if(rep->c->tcp_req_info) {
|
||||
if(!tcp_req_info_add_meshstate(rep->c->tcp_req_info, mesh, s)) {
|
||||
log_err("mesh_new_client: out of memory add tcpreqinfo");
|
||||
goto servfail_mem;
|
||||
}
|
||||
}
|
||||
added_tcp = 1;
|
||||
if(rep->c->use_h2) {
|
||||
http2_stream_add_meshstate(rep->c->h2_stream, mesh, s);
|
||||
} else if(rep->c->type == comm_doq && rep->doq_stream) {
|
||||
doq_stream_add_meshstate(rep->doq_stream, mesh, s);
|
||||
}
|
||||
/* add serve expired timer if required and not already there */
|
||||
if(timeout && !mesh_serve_expired_init(s, timeout)) {
|
||||
@@ -569,6 +616,8 @@ void mesh_new_client(struct mesh_area* mesh, struct query_info* qinfo,
|
||||
}
|
||||
}
|
||||
#endif
|
||||
/* Since the acccounting now happens,
|
||||
* added_reply_without_accounting = 0; but that is not used. */
|
||||
infra_wait_limit_inc(mesh->env->infra_cache, rep, *mesh->env->now,
|
||||
mesh->env->cfg);
|
||||
/* update statistics */
|
||||
@@ -605,7 +654,14 @@ servfail_mem:
|
||||
qinfo, qid, qflags, edns);
|
||||
if(rep->c->use_h2)
|
||||
http2_stream_remove_mesh_state(rep->c->h2_stream);
|
||||
else if(rep->c->type == comm_doq && rep->doq_stream)
|
||||
doq_stream_remove_mesh_state(rep->doq_stream);
|
||||
comm_point_send_reply(rep);
|
||||
if(added_reply_without_accounting) {
|
||||
mesh_remove_reply_without_accounting(s, repadded);
|
||||
if(added_tcp && rep->c->tcp_req_info)
|
||||
tcp_req_info_remove_mesh_state(rep->c->tcp_req_info, s);
|
||||
}
|
||||
if(added)
|
||||
mesh_state_delete(&s->s);
|
||||
return;
|
||||
@@ -614,7 +670,8 @@ servfail_mem:
|
||||
int
|
||||
mesh_new_callback(struct mesh_area* mesh, struct query_info* qinfo,
|
||||
uint16_t qflags, struct edns_data* edns, sldns_buffer* buf,
|
||||
uint16_t qid, mesh_cb_func_type cb, void* cb_arg, int rpz_passthru)
|
||||
uint16_t qid, mesh_cb_func_type cb, void* cb_arg, int rpz_passthru,
|
||||
void** unique_info)
|
||||
{
|
||||
struct mesh_state* s = NULL;
|
||||
int unique = unique_mesh_state(edns->opt_list_in, mesh->env);
|
||||
@@ -623,6 +680,7 @@ mesh_new_callback(struct mesh_area* mesh, struct query_info* qinfo,
|
||||
int was_detached = 0;
|
||||
int was_noreply = 0;
|
||||
int added = 0;
|
||||
struct mesh_cb* add_cb = NULL;
|
||||
uint16_t mesh_flags = qflags&(BIT_RD|BIT_CD);
|
||||
if(!unique)
|
||||
s = mesh_area_find(mesh, NULL, qinfo, mesh_flags, 0, 0);
|
||||
@@ -668,13 +726,14 @@ mesh_new_callback(struct mesh_area* mesh, struct query_info* qinfo,
|
||||
}
|
||||
}
|
||||
/* add reply to s */
|
||||
if(!mesh_state_add_cb(s, edns, buf, cb, cb_arg, qid, qflags)) {
|
||||
if(!mesh_state_add_cb(s, edns, buf, cb, cb_arg, qid, qflags, &add_cb)) {
|
||||
if(added)
|
||||
mesh_state_delete(&s->s);
|
||||
return 0;
|
||||
}
|
||||
/* add serve expired timer if not already there */
|
||||
if(timeout && !mesh_serve_expired_init(s, timeout)) {
|
||||
mesh_remove_callback_without_accounting(s, add_cb);
|
||||
if(added)
|
||||
mesh_state_delete(&s->s);
|
||||
return 0;
|
||||
@@ -685,6 +744,7 @@ mesh_new_callback(struct mesh_area* mesh, struct query_info* qinfo,
|
||||
(mesh->env->cachedb_enabled &&
|
||||
mesh->env->cfg->cachedb_check_when_serve_expired)) {
|
||||
if(!mesh_serve_expired_init(s, -1)) {
|
||||
mesh_remove_callback_without_accounting(s, add_cb);
|
||||
if(added)
|
||||
mesh_state_delete(&s->s);
|
||||
return 0;
|
||||
@@ -700,6 +760,8 @@ mesh_new_callback(struct mesh_area* mesh, struct query_info* qinfo,
|
||||
mesh->num_reply_states ++;
|
||||
}
|
||||
mesh->num_reply_addrs++;
|
||||
if(unique_info)
|
||||
*unique_info = s->unique;
|
||||
if(added)
|
||||
mesh_run(mesh, s, module_event_new, NULL);
|
||||
return 1;
|
||||
@@ -903,33 +965,9 @@ void mesh_report_reply(struct mesh_area* mesh, struct outbound_entry* e,
|
||||
mesh_run(mesh, e->qstate->mesh_info, event, e);
|
||||
}
|
||||
|
||||
/** copy strlist to region */
|
||||
static struct config_strlist*
|
||||
cfg_region_strlist_copy(struct regional* region, struct config_strlist* list)
|
||||
{
|
||||
struct config_strlist* result = NULL, *last = NULL, *s = list;
|
||||
while(s) {
|
||||
struct config_strlist* n = regional_alloc_zero(region,
|
||||
sizeof(*n));
|
||||
if(!n)
|
||||
return NULL;
|
||||
n->str = regional_strdup(region, s->str);
|
||||
if(!n->str)
|
||||
return NULL;
|
||||
if(last)
|
||||
last->next = n;
|
||||
else result = n;
|
||||
last = n;
|
||||
s = s->next;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
/** Copy the client info to the query region. */
|
||||
static struct respip_client_info*
|
||||
struct respip_client_info*
|
||||
mesh_copy_client_info(struct regional* region, struct respip_client_info* cinfo)
|
||||
{
|
||||
size_t i;
|
||||
struct respip_client_info* client_info;
|
||||
client_info = regional_alloc_init(region, cinfo, sizeof(*cinfo));
|
||||
if(!client_info)
|
||||
@@ -948,20 +986,13 @@ mesh_copy_client_info(struct regional* region, struct respip_client_info* cinfo)
|
||||
if(!client_info->tag_actions)
|
||||
return NULL;
|
||||
}
|
||||
if(cinfo->tag_datas) {
|
||||
client_info->tag_datas = regional_alloc_zero(region,
|
||||
sizeof(struct config_strlist*)*cinfo->tag_datas_size);
|
||||
if(!client_info->tag_datas)
|
||||
return NULL;
|
||||
for(i=0; i<cinfo->tag_datas_size; i++) {
|
||||
if(cinfo->tag_datas[i]) {
|
||||
client_info->tag_datas[i] = cfg_region_strlist_copy(
|
||||
region, cinfo->tag_datas[i]);
|
||||
if(!client_info->tag_datas[i])
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
}
|
||||
/* tag_datas is owned by the matched acl_addr in config_file; its
|
||||
* lifetime is until config reload, which tears down all mesh states
|
||||
* first. Keep the original pointer so client_info_compare()
|
||||
* can recognise two states from the same ACL entry. */
|
||||
/* fast reload insists on dropping the queries when interface-tag-data
|
||||
* or access-control-tag-data are changed. */
|
||||
/* client_info->tag_datas already copied by regional_alloc_init above */
|
||||
if(cinfo->view) {
|
||||
/* Do not copy the view pointer but store a name instead.
|
||||
* The name is looked up later when done, this means that
|
||||
@@ -971,6 +1002,11 @@ mesh_copy_client_info(struct regional* region, struct respip_client_info* cinfo)
|
||||
cinfo->view->name);
|
||||
if(!client_info->view_name)
|
||||
return NULL;
|
||||
} else if(cinfo->view_name) {
|
||||
client_info->view_name = regional_strdup(region,
|
||||
cinfo->view_name);
|
||||
if(!client_info->view_name)
|
||||
return NULL;
|
||||
}
|
||||
return client_info;
|
||||
}
|
||||
@@ -1061,6 +1097,18 @@ mesh_state_make_unique(struct mesh_state* mstate)
|
||||
mstate->unique = mstate;
|
||||
}
|
||||
|
||||
/** pop a reply from the reply list, if there are any. */
|
||||
static struct mesh_reply*
|
||||
mesh_reply_list_pop_first(struct mesh_state* mstate)
|
||||
{
|
||||
if(mstate->reply_list) {
|
||||
struct mesh_reply* r = mstate->reply_list;
|
||||
mstate->reply_list = r->next;
|
||||
return r;
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
void
|
||||
mesh_state_cleanup(struct mesh_state* mstate)
|
||||
{
|
||||
@@ -1076,23 +1124,30 @@ mesh_state_cleanup(struct mesh_state* mstate)
|
||||
}
|
||||
/* drop unsent replies */
|
||||
if(!mstate->replies_sent) {
|
||||
struct mesh_reply* rep = mstate->reply_list;
|
||||
struct mesh_reply* rep;
|
||||
struct mesh_cb* cb;
|
||||
/* One http2 stream could bring down its comm_point along with
|
||||
* the other streams which could share the same query. Do all
|
||||
* the http2 stream bookkeeping upfront. */
|
||||
for(; rep; rep=rep->next) {
|
||||
if(rep->query_reply.c->use_h2)
|
||||
http2_stream_remove_mesh_state(rep->h2_stream);
|
||||
}
|
||||
rep = mstate->reply_list;
|
||||
/* in tcp_req_info, the mstates linked are removed, but
|
||||
* the reply_list is now NULL, so the remove-from-empty-list
|
||||
* takes no time and also it does not do the mesh accounting */
|
||||
mstate->reply_list = NULL;
|
||||
for(; rep; rep=rep->next) {
|
||||
/* Pop items from the list, that means there is no iterator.
|
||||
* And then items can be removed from the reply list, from
|
||||
* like comm_point_drop_reply and comm_point_close calls.
|
||||
* As the tcp_req_info and http2 code drops the entire
|
||||
* connection. That could delete mesh_reply items previous and
|
||||
* after the current state. The previous items are already
|
||||
* popped. And the next items can be altered, like to when a
|
||||
* connection has more replies on the reply list.
|
||||
* The current item is also popped so the code needs to
|
||||
* remove its references. */
|
||||
while((rep = mesh_reply_list_pop_first(mstate)) != NULL) {
|
||||
infra_wait_limit_dec(mesh->env->infra_cache,
|
||||
&rep->query_reply, mesh->env->cfg);
|
||||
if(rep->query_reply.c->tcp_req_info)
|
||||
tcp_req_info_remove_mesh_state(
|
||||
rep->query_reply.c->tcp_req_info,
|
||||
mstate);
|
||||
else if(rep->query_reply.c->use_h2)
|
||||
http2_stream_remove_mesh_state(rep->h2_stream);
|
||||
else if(rep->query_reply.doq_stream)
|
||||
doq_stream_remove_mesh_state(
|
||||
rep->query_reply.doq_stream);
|
||||
comm_point_drop_reply(&rep->query_reply);
|
||||
log_assert(mesh->num_reply_addrs > 0);
|
||||
mesh->num_reply_addrs--;
|
||||
@@ -1229,6 +1284,9 @@ int mesh_add_sub(struct module_qstate* qstate, struct query_info* qinfo,
|
||||
log_err("mesh_attach_sub: out of memory");
|
||||
return 0;
|
||||
}
|
||||
/* inherit RPZ passthru from the parent so respip on the sub
|
||||
* sees the same client-IP/qname PASSTHRU decision */
|
||||
(*sub)->s.rpz_passthru = qstate->rpz_passthru;
|
||||
#ifdef UNBOUND_DEBUG
|
||||
n =
|
||||
#else
|
||||
@@ -1453,12 +1511,6 @@ mesh_send_reply(struct mesh_state* m, int rcode, struct reply_info* rep,
|
||||
struct timeval end_time;
|
||||
struct timeval duration;
|
||||
int secure;
|
||||
/* briefly set the replylist to null in case the
|
||||
* meshsendreply calls tcpreqinfo sendreply that
|
||||
* comm_point_drops because of size, and then the
|
||||
* null stops the mesh state remove and thus
|
||||
* reply_list modification and accounting */
|
||||
struct mesh_reply* rlist = m->reply_list;
|
||||
|
||||
/* rpz: apply actions */
|
||||
rcode = mesh_is_udp(r) && mesh_is_rpz_respip_tcponly_action(m)
|
||||
@@ -1484,6 +1536,10 @@ mesh_send_reply(struct mesh_state* m, int rcode, struct reply_info* rep,
|
||||
* for HTTP/2 stream to refer to mesh state, in case
|
||||
* connection gets cleanup before HTTP/2 stream close. */
|
||||
r->h2_stream->mesh_state = NULL;
|
||||
#ifdef HAVE_NGTCP2
|
||||
} else if(r->query_reply.doq_stream) {
|
||||
r->query_reply.doq_stream->mesh_state = NULL;
|
||||
#endif
|
||||
}
|
||||
/* send the reply */
|
||||
/* We don't reuse the encoded answer if:
|
||||
@@ -1511,9 +1567,7 @@ mesh_send_reply(struct mesh_state* m, int rcode, struct reply_info* rep,
|
||||
sldns_buffer_write_at(r_buffer, 0, &r->qid, sizeof(uint16_t));
|
||||
sldns_buffer_write_at(r_buffer, 12, r->qname,
|
||||
m->s.qinfo.qname_len);
|
||||
m->reply_list = NULL;
|
||||
comm_point_send_reply(&r->query_reply);
|
||||
m->reply_list = rlist;
|
||||
} else if(rcode) {
|
||||
m->s.qinfo.qname = r->qname;
|
||||
m->s.qinfo.local_alias = r->local_alias;
|
||||
@@ -1535,9 +1589,7 @@ mesh_send_reply(struct mesh_state* m, int rcode, struct reply_info* rep,
|
||||
}
|
||||
error_encode(r_buffer, rcode, &m->s.qinfo, r->qid,
|
||||
r->qflags, &r->edns);
|
||||
m->reply_list = NULL;
|
||||
comm_point_send_reply(&r->query_reply);
|
||||
m->reply_list = rlist;
|
||||
} else {
|
||||
size_t udp_size = r->edns.udp_size;
|
||||
r->edns.edns_version = EDNS_ADVERTISED_VERSION;
|
||||
@@ -1573,9 +1625,7 @@ mesh_send_reply(struct mesh_state* m, int rcode, struct reply_info* rep,
|
||||
error_encode(r_buffer, LDNS_RCODE_SERVFAIL,
|
||||
&m->s.qinfo, r->qid, r->qflags, &r->edns);
|
||||
}
|
||||
m->reply_list = NULL;
|
||||
comm_point_send_reply(&r->query_reply);
|
||||
m->reply_list = rlist;
|
||||
}
|
||||
infra_wait_limit_dec(m->s.env->infra_cache, &r->query_reply,
|
||||
m->s.env->cfg);
|
||||
@@ -1638,9 +1688,9 @@ static void dns_error_reporting(struct module_qstate* qstate,
|
||||
opt = edns_opt_list_find(qstate->edns_opts_back_in,
|
||||
LDNS_EDNS_REPORT_CHANNEL);
|
||||
if(!opt) return;
|
||||
agent_domain_len = opt->opt_len;
|
||||
agent_domain = opt->opt_data;
|
||||
if(dname_valid(agent_domain, agent_domain_len) < 3) {
|
||||
agent_domain_len = dname_valid(agent_domain, opt->opt_len);
|
||||
if(agent_domain_len < 3) {
|
||||
/* The agent domain needs to be a valid dname that is not the
|
||||
* root; from RFC9567. */
|
||||
return;
|
||||
@@ -1727,6 +1777,7 @@ void mesh_query_done(struct mesh_state* mstate)
|
||||
struct reply_info* rep = (mstate->s.return_msg?
|
||||
mstate->s.return_msg->rep:NULL);
|
||||
struct timeval tv = {0, 0};
|
||||
struct mesh_area* mesh = mstate->s.env->mesh;
|
||||
int i = 0;
|
||||
/* No need for the serve expired timer anymore; we are going to reply. */
|
||||
if(mstate->s.serve_expired_data) {
|
||||
@@ -1747,10 +1798,22 @@ void mesh_query_done(struct mesh_state* mstate)
|
||||
}
|
||||
}
|
||||
|
||||
if(mstate->reply_list && mstate->s.env->cfg->dns_error_reporting)
|
||||
if(mstate->reply_list && mstate->s.env->cfg->dns_error_reporting
|
||||
&& (!rep || rep->security != sec_status_secure))
|
||||
dns_error_reporting(&mstate->s, rep);
|
||||
|
||||
for(r = mstate->reply_list; r; r = r->next) {
|
||||
while((r = mesh_reply_list_pop_first(mstate)) != NULL) {
|
||||
|
||||
/* it was not detached (because it had a reply list), could be now */
|
||||
if(!mstate->reply_list && !mstate->cb_list
|
||||
&& mstate->super_set.count == 0) {
|
||||
mesh->num_detached_states++;
|
||||
}
|
||||
/* if not replies any more in mstate, it is no longer a reply_state */
|
||||
if(!mstate->reply_list && !mstate->cb_list) {
|
||||
log_assert(mesh->num_reply_states > 0);
|
||||
mesh->num_reply_states--;
|
||||
}
|
||||
if(mesh_is_udp(r)) {
|
||||
/* For UDP queries, the old replies are discarded.
|
||||
* This stops a large volume of old replies from
|
||||
@@ -1765,20 +1828,18 @@ void mesh_query_done(struct mesh_state* mstate)
|
||||
((int)old.tv_sec)*1000+((int)old.tv_usec)/1000 >
|
||||
mstate->s.env->cfg->discard_timeout) {
|
||||
/* Drop the reply, it is too old */
|
||||
/* briefly set the reply_list to NULL, so that the
|
||||
* tcp req info cleanup routine that calls the mesh
|
||||
* to deregister the meshstate for it is not done
|
||||
* because the list is NULL and also accounting is not
|
||||
* done there, but instead we do that here. */
|
||||
struct mesh_reply* reply_list = mstate->reply_list;
|
||||
verbose(VERB_ALGO, "drop reply, it is older than discard-timeout");
|
||||
infra_wait_limit_dec(mstate->s.env->infra_cache,
|
||||
&r->query_reply, mstate->s.env->cfg);
|
||||
mstate->reply_list = NULL;
|
||||
if(r->query_reply.c->use_h2)
|
||||
if(r->query_reply.c->tcp_req_info)
|
||||
tcp_req_info_remove_mesh_state(
|
||||
r->query_reply.c->tcp_req_info,
|
||||
mstate);
|
||||
else if(r->query_reply.c->use_h2)
|
||||
http2_stream_remove_mesh_state(r->h2_stream);
|
||||
else if(r->query_reply.doq_stream)
|
||||
doq_stream_remove_mesh_state(r->query_reply.doq_stream);
|
||||
comm_point_drop_reply(&r->query_reply);
|
||||
mstate->reply_list = reply_list;
|
||||
log_assert(mstate->s.env->mesh->num_reply_addrs > 0);
|
||||
mstate->s.env->mesh->num_reply_addrs--;
|
||||
mstate->s.env->mesh->num_queries_discard_timeout++;
|
||||
@@ -1803,20 +1864,17 @@ void mesh_query_done(struct mesh_state* mstate)
|
||||
/* if this query is determined to be dropped during the
|
||||
* mesh processing, this is the point to take that action. */
|
||||
if(mstate->s.is_drop) {
|
||||
/* briefly set the reply_list to NULL, so that the
|
||||
* tcp req info cleanup routine that calls the mesh
|
||||
* to deregister the meshstate for it is not done
|
||||
* because the list is NULL and also accounting is not
|
||||
* done there, but instead we do that here. */
|
||||
struct mesh_reply* reply_list = mstate->reply_list;
|
||||
infra_wait_limit_dec(mstate->s.env->infra_cache,
|
||||
&r->query_reply, mstate->s.env->cfg);
|
||||
mstate->reply_list = NULL;
|
||||
if(r->query_reply.c->use_h2) {
|
||||
if(r->query_reply.c->tcp_req_info) {
|
||||
tcp_req_info_remove_mesh_state(
|
||||
r->query_reply.c->tcp_req_info, mstate);
|
||||
} else if(r->query_reply.c->use_h2) {
|
||||
http2_stream_remove_mesh_state(r->h2_stream);
|
||||
} else if(r->query_reply.doq_stream) {
|
||||
doq_stream_remove_mesh_state(r->query_reply.doq_stream);
|
||||
}
|
||||
comm_point_drop_reply(&r->query_reply);
|
||||
mstate->reply_list = reply_list;
|
||||
log_assert(mstate->s.env->mesh->num_reply_addrs > 0);
|
||||
mstate->s.env->mesh->num_reply_addrs--;
|
||||
} else {
|
||||
@@ -1857,18 +1915,6 @@ void mesh_query_done(struct mesh_state* mstate)
|
||||
}
|
||||
}
|
||||
|
||||
/* Mesh area accounting */
|
||||
if(mstate->reply_list) {
|
||||
mstate->reply_list = NULL;
|
||||
if(!mstate->reply_list && !mstate->cb_list) {
|
||||
/* was a reply state, not anymore */
|
||||
log_assert(mstate->s.env->mesh->num_reply_states > 0);
|
||||
mstate->s.env->mesh->num_reply_states--;
|
||||
}
|
||||
if(!mstate->reply_list && !mstate->cb_list &&
|
||||
mstate->super_set.count == 0)
|
||||
mstate->s.env->mesh->num_detached_states++;
|
||||
}
|
||||
mstate->replies_sent = 1;
|
||||
|
||||
while((c = mstate->cb_list) != NULL) {
|
||||
@@ -1926,6 +1972,25 @@ struct mesh_state* mesh_area_find(struct mesh_area* mesh,
|
||||
return result;
|
||||
}
|
||||
|
||||
struct mesh_state* mesh_area_find_unique(struct mesh_area* mesh,
|
||||
struct respip_client_info* cinfo, struct query_info* qinfo,
|
||||
uint16_t qflags, int prime, int valrec, void* unique_info)
|
||||
{
|
||||
struct mesh_state key;
|
||||
struct mesh_state* result;
|
||||
|
||||
key.node.key = &key;
|
||||
key.s.is_priming = prime;
|
||||
key.s.is_valrec = valrec;
|
||||
key.s.qinfo = *qinfo;
|
||||
key.s.query_flags = qflags;
|
||||
key.unique = (struct mesh_state*)unique_info;
|
||||
key.s.client_info = cinfo;
|
||||
|
||||
result = (struct mesh_state*)rbtree_search(&mesh->all, &key);
|
||||
return result;
|
||||
}
|
||||
|
||||
/** remove mesh state callback */
|
||||
int mesh_state_del_cb(struct mesh_state* s, mesh_cb_func_type cb, void* cb_arg)
|
||||
{
|
||||
@@ -1947,7 +2012,7 @@ int mesh_state_del_cb(struct mesh_state* s, mesh_cb_func_type cb, void* cb_arg)
|
||||
|
||||
int mesh_state_add_cb(struct mesh_state* s, struct edns_data* edns,
|
||||
sldns_buffer* buf, mesh_cb_func_type cb, void* cb_arg,
|
||||
uint16_t qid, uint16_t qflags)
|
||||
uint16_t qid, uint16_t qflags, struct mesh_cb** result)
|
||||
{
|
||||
struct mesh_cb* r = regional_alloc(s->s.region,
|
||||
sizeof(struct mesh_cb));
|
||||
@@ -1971,13 +2036,14 @@ int mesh_state_add_cb(struct mesh_state* s, struct edns_data* edns,
|
||||
r->qflags = qflags;
|
||||
r->next = s->cb_list;
|
||||
s->cb_list = r;
|
||||
*result = r;
|
||||
return 1;
|
||||
|
||||
}
|
||||
|
||||
int mesh_state_add_reply(struct mesh_state* s, struct edns_data* edns,
|
||||
struct comm_reply* rep, uint16_t qid, uint16_t qflags,
|
||||
const struct query_info* qinfo)
|
||||
const struct query_info* qinfo, struct mesh_reply** result)
|
||||
{
|
||||
struct mesh_reply* r = regional_alloc(s->s.region,
|
||||
sizeof(struct mesh_reply));
|
||||
@@ -2009,6 +2075,8 @@ int mesh_state_add_reply(struct mesh_state* s, struct edns_data* edns,
|
||||
if(rep->c->use_h2)
|
||||
r->h2_stream = rep->c->h2_stream;
|
||||
else r->h2_stream = NULL;
|
||||
if(rep->c->type != comm_doq)
|
||||
r->query_reply.doq_stream = NULL;
|
||||
|
||||
/* Data related to local alias stored in 'qinfo' (if any) is ephemeral
|
||||
* and can be different for different original queries (even if the
|
||||
@@ -2056,6 +2124,7 @@ int mesh_state_add_reply(struct mesh_state* s, struct edns_data* edns,
|
||||
r->local_alias = NULL;
|
||||
|
||||
s->reply_list = r;
|
||||
*result = r;
|
||||
return 1;
|
||||
}
|
||||
|
||||
@@ -2213,8 +2282,29 @@ void mesh_run(struct mesh_area* mesh, struct mesh_state* mstate,
|
||||
enum module_ev ev, struct outbound_entry* e)
|
||||
{
|
||||
enum module_ext_state s;
|
||||
int numrun = 0;
|
||||
verbose(VERB_ALGO, "mesh_run: start");
|
||||
while(mstate) {
|
||||
if(numrun++ > MESH_MAX_RUN_ITER) {
|
||||
/* These modules are too much to activate, stop them.*/
|
||||
log_err("Too many module run iterations, deleting");
|
||||
while(mstate) {
|
||||
/* notify supers */
|
||||
if(mstate->super_set.count > 0) {
|
||||
verbose(VERB_ALGO, "notify supers of failure");
|
||||
mstate->s.return_msg = NULL;
|
||||
mstate->s.return_rcode = LDNS_RCODE_SERVFAIL;
|
||||
mesh_walk_supers(mesh, mstate);
|
||||
}
|
||||
mesh_state_delete(&mstate->s);
|
||||
if(mesh->run.count > 0) {
|
||||
/* pop random element off the runnable tree */
|
||||
mstate = (struct mesh_state*)mesh->run.root->key;
|
||||
(void)rbtree_delete(&mesh->run, mstate);
|
||||
} else mstate = NULL;
|
||||
}
|
||||
break;
|
||||
}
|
||||
/* run the module */
|
||||
fptr_ok(fptr_whitelist_mod_operate(
|
||||
mesh->mods.mod[mstate->s.curmod]->operate));
|
||||
@@ -2366,7 +2456,8 @@ void mesh_list_remove(struct mesh_state* m, struct mesh_state** fp,
|
||||
}
|
||||
|
||||
void mesh_state_remove_reply(struct mesh_area* mesh, struct mesh_state* m,
|
||||
struct comm_point* cp)
|
||||
struct comm_point* cp, struct http2_stream* h2_stream,
|
||||
struct doq_stream* doq_stream)
|
||||
{
|
||||
struct mesh_reply* n, *prev = NULL;
|
||||
n = m->reply_list;
|
||||
@@ -2374,7 +2465,9 @@ void mesh_state_remove_reply(struct mesh_area* mesh, struct mesh_state* m,
|
||||
* there is no accounting twice */
|
||||
if(!n) return; /* nothing to remove, also no accounting needed */
|
||||
while(n) {
|
||||
if(n->query_reply.c == cp) {
|
||||
if(n->query_reply.c == cp
|
||||
&& (!h2_stream || n->h2_stream == h2_stream)
|
||||
&& (!doq_stream || n->query_reply.doq_stream == doq_stream)) {
|
||||
/* unlink it */
|
||||
if(prev) prev->next = n->next;
|
||||
else m->reply_list = n->next;
|
||||
@@ -2387,6 +2480,10 @@ void mesh_state_remove_reply(struct mesh_area* mesh, struct mesh_state* m,
|
||||
* share the same comm_point); make sure the streams
|
||||
* don't point back. */
|
||||
if(n->h2_stream) n->h2_stream->mesh_state = NULL;
|
||||
#ifdef HAVE_NGTCP2
|
||||
if(n->query_reply.doq_stream)
|
||||
n->query_reply.doq_stream->mesh_state = NULL;
|
||||
#endif
|
||||
|
||||
/* prev = prev; */
|
||||
n = n->next;
|
||||
@@ -2407,7 +2504,6 @@ void mesh_state_remove_reply(struct mesh_area* mesh, struct mesh_state* m,
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
static int
|
||||
apply_respip_action(struct module_qstate* qstate,
|
||||
const struct query_info* qinfo, struct respip_client_info* cinfo,
|
||||
@@ -2427,9 +2523,10 @@ apply_respip_action(struct module_qstate* qstate,
|
||||
|
||||
/* xxx_deny actions mean dropping the reply, unless the original reply
|
||||
* was redirected to response-ip data. */
|
||||
if((actinfo->action == respip_deny ||
|
||||
if(actinfo->action == respip_always_deny ||
|
||||
((actinfo->action == respip_deny ||
|
||||
actinfo->action == respip_inform_deny) &&
|
||||
*encode_repp == rep)
|
||||
*encode_repp == rep))
|
||||
*encode_repp = NULL;
|
||||
|
||||
return 1;
|
||||
@@ -2494,12 +2591,15 @@ mesh_serve_expired_callback(void* arg)
|
||||
qstate->client_info, &actinfo, msg->rep, &alias_rrset, &encode_rep,
|
||||
qstate->env->auth_zones)) {
|
||||
return;
|
||||
} else if(partial_rep &&
|
||||
!respip_merge_cname(partial_rep, &qstate->qinfo, msg->rep,
|
||||
} else if(partial_rep) {
|
||||
if(!respip_merge_cname(partial_rep, &qstate->qinfo, msg->rep,
|
||||
qstate->client_info, must_validate, &encode_rep, qstate->region,
|
||||
qstate->env->auth_zones, qstate->env->views,
|
||||
qstate->env->respip_set)) {
|
||||
return;
|
||||
return;
|
||||
}
|
||||
/* merge succeeded; final reply, no further alias pass */
|
||||
partial_rep = NULL;
|
||||
}
|
||||
if(!encode_rep || alias_rrset) {
|
||||
if(!encode_rep) {
|
||||
@@ -2510,6 +2610,7 @@ mesh_serve_expired_callback(void* arg)
|
||||
partial_rep = encode_rep;
|
||||
}
|
||||
}
|
||||
msg->rep = encode_rep;
|
||||
/* We've found a partial reply ending with an
|
||||
* alias. Replace the lookup qinfo for the
|
||||
* alias target and lookup the cache again to
|
||||
@@ -2535,29 +2636,41 @@ mesh_serve_expired_callback(void* arg)
|
||||
if(verbosity >= VERB_ALGO)
|
||||
log_dns_msg("Serve expired lookup", &qstate->qinfo, msg->rep);
|
||||
|
||||
for(r = mstate->reply_list; r; r = r->next) {
|
||||
struct timeval old;
|
||||
timeval_subtract(&old, mstate->s.env->now_tv, &r->start_time);
|
||||
if(mstate->s.env->cfg->discard_timeout != 0 &&
|
||||
while((r = mesh_reply_list_pop_first(mstate)) != NULL) {
|
||||
|
||||
/* it was not detached (because it had a reply list), could be now */
|
||||
if(!mstate->reply_list && !mstate->cb_list
|
||||
&& mstate->super_set.count == 0) {
|
||||
mesh->num_detached_states++;
|
||||
}
|
||||
/* if not replies any more in mstate, it is no longer a reply_state */
|
||||
if(!mstate->reply_list && !mstate->cb_list) {
|
||||
log_assert(mesh->num_reply_states > 0);
|
||||
mesh->num_reply_states--;
|
||||
}
|
||||
if(mesh_is_udp(r)) {
|
||||
struct timeval old;
|
||||
timeval_subtract(&old, mstate->s.env->now_tv, &r->start_time);
|
||||
if(mstate->s.env->cfg->discard_timeout != 0 &&
|
||||
((int)old.tv_sec)*1000+((int)old.tv_usec)/1000 >
|
||||
mstate->s.env->cfg->discard_timeout) {
|
||||
/* Drop the reply, it is too old */
|
||||
/* briefly set the reply_list to NULL, so that the
|
||||
* tcp req info cleanup routine that calls the mesh
|
||||
* to deregister the meshstate for it is not done
|
||||
* because the list is NULL and also accounting is not
|
||||
* done there, but instead we do that here. */
|
||||
struct mesh_reply* reply_list = mstate->reply_list;
|
||||
verbose(VERB_ALGO, "drop reply, it is older than discard-timeout");
|
||||
infra_wait_limit_dec(mstate->s.env->infra_cache,
|
||||
&r->query_reply, mstate->s.env->cfg);
|
||||
mstate->reply_list = NULL;
|
||||
if(r->query_reply.c->use_h2)
|
||||
if(r->query_reply.c->tcp_req_info)
|
||||
tcp_req_info_remove_mesh_state(
|
||||
r->query_reply.c->tcp_req_info, mstate);
|
||||
else if(r->query_reply.c->use_h2)
|
||||
http2_stream_remove_mesh_state(r->h2_stream);
|
||||
else if(r->query_reply.doq_stream)
|
||||
doq_stream_remove_mesh_state(r->query_reply.doq_stream);
|
||||
comm_point_drop_reply(&r->query_reply);
|
||||
mstate->reply_list = reply_list;
|
||||
log_assert(mstate->s.env->mesh->num_reply_addrs > 0);
|
||||
mstate->s.env->mesh->num_reply_addrs--;
|
||||
mstate->s.env->mesh->num_queries_discard_timeout++;
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
i++;
|
||||
@@ -2590,8 +2703,7 @@ mesh_serve_expired_callback(void* arg)
|
||||
if(r->query_reply.c->tcp_req_info)
|
||||
tcp_req_info_remove_mesh_state(r->query_reply.c->tcp_req_info, mstate);
|
||||
/* mesh_send_reply removed mesh state from http2_stream. */
|
||||
infra_wait_limit_dec(mstate->s.env->infra_cache,
|
||||
&r->query_reply, mstate->s.env->cfg);
|
||||
/* mesh_send_reply decremented wait_limit. */
|
||||
prev = r;
|
||||
prev_buffer = r_buffer;
|
||||
}
|
||||
@@ -2610,18 +2722,6 @@ mesh_serve_expired_callback(void* arg)
|
||||
}
|
||||
}
|
||||
|
||||
/* Mesh area accounting */
|
||||
if(mstate->reply_list) {
|
||||
mstate->reply_list = NULL;
|
||||
if(!mstate->reply_list && !mstate->cb_list) {
|
||||
log_assert(mesh->num_reply_states > 0);
|
||||
mesh->num_reply_states--;
|
||||
if(mstate->super_set.count == 0) {
|
||||
mesh->num_detached_states++;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
while((c = mstate->cb_list) != NULL) {
|
||||
/* take this cb off the list; so that the list can be
|
||||
* changed, eg. by adds from the callback routine */
|
||||
@@ -2654,13 +2754,30 @@ int mesh_jostle_exceeded(struct mesh_area* mesh)
|
||||
}
|
||||
|
||||
void mesh_remove_callback(struct mesh_area* mesh, struct query_info* qinfo,
|
||||
uint16_t qflags, mesh_cb_func_type cb, void* cb_arg)
|
||||
uint16_t qflags, mesh_cb_func_type cb, void* cb_arg, void* unique_info)
|
||||
{
|
||||
struct mesh_state* s = NULL;
|
||||
s = mesh_area_find(mesh, NULL, qinfo, qflags&(BIT_RD|BIT_CD), 0, 0);
|
||||
if(!s) return;
|
||||
if(!mesh_state_del_cb(s, cb, cb_arg)) return;
|
||||
if(s && mesh_state_del_cb(s, cb, cb_arg))
|
||||
goto removed;
|
||||
if(unique_info) {
|
||||
s = mesh_area_find_unique(mesh, NULL, qinfo,
|
||||
qflags&(BIT_RD|BIT_CD), 0, 0, unique_info);
|
||||
if(s && mesh_state_del_cb(s, cb, cb_arg))
|
||||
goto removed;
|
||||
}
|
||||
/* mesh_area_find builds key.unique=NULL and cannot match a state
|
||||
* created with mesh_state_make_unique (e.g. subnetcache sets
|
||||
* env->unique_mesh). Fall back to a linear scan; cb+cb_arg is an
|
||||
* exact key (mesh_state_del_cb compares both).
|
||||
* This works for both lookups for zonemd and for hostname authzone. */
|
||||
RBTREE_FOR(s, struct mesh_state*, &mesh->all) {
|
||||
if(s->cb_list && mesh_state_del_cb(s, cb, cb_arg))
|
||||
goto removed;
|
||||
}
|
||||
return;
|
||||
|
||||
removed:
|
||||
/* It was in the list and removed. */
|
||||
log_assert(mesh->num_reply_addrs > 0);
|
||||
mesh->num_reply_addrs--;
|
||||
|
||||
+44
-5
@@ -69,6 +69,13 @@ struct respip_client_info;
|
||||
*/
|
||||
#define MESH_MAX_ACTIVATION 10000
|
||||
|
||||
/**
|
||||
* Maximum number of mesh state run items. These are different modules
|
||||
* activated during a mesh run. Any more is likely an infinite loop
|
||||
* in the module. It is then terminated, and states are deleted.
|
||||
*/
|
||||
#define MESH_MAX_RUN_ITER 10000
|
||||
|
||||
/**
|
||||
* Max number of references-to-references-to-references.. search size.
|
||||
* Any more is treated like 'too large', and the creation of a new
|
||||
@@ -342,11 +349,14 @@ void mesh_new_client(struct mesh_area* mesh, struct query_info* qinfo,
|
||||
* @param cb_arg: callback user arg.
|
||||
* @param rpz_passthru: if true, the rpz passthru was previously found and
|
||||
* further rpz processing is stopped.
|
||||
* @param unique_info: if nonnull, unique info is passed back to be used
|
||||
* for the callback remove call. It does not need to be deallocated.
|
||||
* @return 0 on error.
|
||||
*/
|
||||
int mesh_new_callback(struct mesh_area* mesh, struct query_info* qinfo,
|
||||
uint16_t qflags, struct edns_data* edns, struct sldns_buffer* buf,
|
||||
uint16_t qid, mesh_cb_func_type cb, void* cb_arg, int rpz_passthru);
|
||||
uint16_t qid, mesh_cb_func_type cb, void* cb_arg, int rpz_passthru,
|
||||
void** unique_info);
|
||||
|
||||
/**
|
||||
* New prefetch message. Create new query state if needed.
|
||||
@@ -543,6 +553,23 @@ struct mesh_state* mesh_area_find(struct mesh_area* mesh,
|
||||
struct respip_client_info* cinfo, struct query_info* qinfo,
|
||||
uint16_t qflags, int prime, int valrec);
|
||||
|
||||
/**
|
||||
* Find a unique mesh state in the mesh area. Pass relevant flags.
|
||||
*
|
||||
* @param mesh: the mesh area to look in.
|
||||
* @param cinfo: if non-NULL client specific info that may affect IP-based
|
||||
* actions that apply to the query result.
|
||||
* @param qinfo: what query
|
||||
* @param qflags: if RD / CD bit is set or not.
|
||||
* @param prime: if it is a priming query.
|
||||
* @param valrec: if it is a validation-recursion query.
|
||||
* @param unique_info: the unique info for the state. NULL can be passed.
|
||||
* @return: mesh state or NULL if not found.
|
||||
*/
|
||||
struct mesh_state* mesh_area_find_unique(struct mesh_area* mesh,
|
||||
struct respip_client_info* cinfo, struct query_info* qinfo,
|
||||
uint16_t qflags, int prime, int valrec, void* unique_info);
|
||||
|
||||
/**
|
||||
* Setup attachment super/sub relation between super and sub mesh state.
|
||||
* The relation must not be present when calling the function.
|
||||
@@ -562,11 +589,12 @@ int mesh_state_attachment(struct mesh_state* super, struct mesh_state* sub);
|
||||
* @param qid: ID of reply.
|
||||
* @param qflags: original query flags.
|
||||
* @param qinfo: original query info.
|
||||
* @param result: the allocated reply structure, for rollback.
|
||||
* @return: 0 on alloc error.
|
||||
*/
|
||||
int mesh_state_add_reply(struct mesh_state* s, struct edns_data* edns,
|
||||
struct comm_reply* rep, uint16_t qid, uint16_t qflags,
|
||||
const struct query_info* qinfo);
|
||||
const struct query_info* qinfo, struct mesh_reply** result);
|
||||
|
||||
/**
|
||||
* Create new callback structure and attach it to a mesh state.
|
||||
@@ -578,11 +606,12 @@ int mesh_state_add_reply(struct mesh_state* s, struct edns_data* edns,
|
||||
* @param cb_arg: callback user arg.
|
||||
* @param qid: ID of reply.
|
||||
* @param qflags: original query flags.
|
||||
* @param result: the allocated callback structure, for rollback.
|
||||
* @return: 0 on alloc error.
|
||||
*/
|
||||
int mesh_state_add_cb(struct mesh_state* s, struct edns_data* edns,
|
||||
struct sldns_buffer* buf, mesh_cb_func_type cb, void* cb_arg,
|
||||
uint16_t qid, uint16_t qflags);
|
||||
uint16_t qid, uint16_t qflags, struct mesh_cb** result);
|
||||
|
||||
/**
|
||||
* Run the mesh. Run all runnable mesh states. Which can create new
|
||||
@@ -683,9 +712,14 @@ void mesh_list_remove(struct mesh_state* m, struct mesh_state** fp,
|
||||
* @param mesh: to update the counters.
|
||||
* @param m: the mesh state.
|
||||
* @param cp: the comm_point to remove from the list.
|
||||
* @param h2_stream: if not NULL, it specifies the h2_stream to match
|
||||
* for the delete.
|
||||
* @param doq_stream: if not NULL, it specifies the doq_stream to match
|
||||
* for the delete.
|
||||
*/
|
||||
void mesh_state_remove_reply(struct mesh_area* mesh, struct mesh_state* m,
|
||||
struct comm_point* cp);
|
||||
struct comm_point* cp, struct http2_stream* h2_stream,
|
||||
struct doq_stream* doq_stream);
|
||||
|
||||
/** Callback for when the serve expired client timer has run out. Tries to
|
||||
* find an expired answer in the cache and reply that to the client.
|
||||
@@ -732,8 +766,13 @@ void mesh_respond_serve_expired(struct mesh_state* mstate);
|
||||
* @param qflags: flags from client query.
|
||||
* @param cb: callback function.
|
||||
* @param cb_arg: callback user arg.
|
||||
* @param unique_info: if not NULL, used to find a unique state for removal.
|
||||
*/
|
||||
void mesh_remove_callback(struct mesh_area* mesh, struct query_info* qinfo,
|
||||
uint16_t qflags, mesh_cb_func_type cb, void* cb_arg);
|
||||
uint16_t qflags, mesh_cb_func_type cb, void* cb_arg, void* unique_info);
|
||||
|
||||
/** Copy the client info to the query region. */
|
||||
struct respip_client_info* mesh_copy_client_info(struct regional* region,
|
||||
struct respip_client_info* cinfo);
|
||||
|
||||
#endif /* SERVICES_MESH_H */
|
||||
|
||||
+381
-72
@@ -208,6 +208,7 @@ static void
|
||||
waiting_tcp_delete(struct waiting_tcp* w)
|
||||
{
|
||||
if(!w) return;
|
||||
free(w->tls_auth_name);
|
||||
if(w->timer)
|
||||
comm_timer_delete(w->timer);
|
||||
free(w);
|
||||
@@ -1480,7 +1481,7 @@ portcomm_loweruse(struct outside_network* outnet, struct port_comm* pc)
|
||||
pif = pc->pif;
|
||||
log_assert(pif->inuse > 0);
|
||||
#ifndef DISABLE_EXPLICIT_PORT_RANDOMISATION
|
||||
pif->avail_ports[pif->avail_total - pif->inuse] = pc->number;
|
||||
shared_ports_return_port(outnet->shared_ports, pif->shpif, pc->number);
|
||||
#endif
|
||||
pif->inuse--;
|
||||
pif->out[pc->index] = pif->out[pif->inuse];
|
||||
@@ -1694,19 +1695,25 @@ create_pending_tcp(struct outside_network* outnet, size_t bufsize)
|
||||
}
|
||||
|
||||
/** setup an outgoing interface, ready address */
|
||||
static int setup_if(struct port_if* pif, const char* addrstr,
|
||||
int* avail, int numavail, size_t numfd)
|
||||
static int setup_if(struct port_if* pif, const char* addrstr, size_t numfd,
|
||||
struct shared_ports* shp)
|
||||
{
|
||||
#ifndef DISABLE_EXPLICIT_PORT_RANDOMISATION
|
||||
pif->avail_total = numavail;
|
||||
pif->avail_ports = (int*)memdup(avail, (size_t)numavail*sizeof(int));
|
||||
if(!pif->avail_ports)
|
||||
return 0;
|
||||
#endif
|
||||
if(!ipstrtoaddr(addrstr, UNBOUND_DNS_PORT, &pif->addr, &pif->addrlen) &&
|
||||
!netblockstrtoaddr(addrstr, UNBOUND_DNS_PORT,
|
||||
&pif->addr, &pif->addrlen, &pif->pfxlen))
|
||||
return 0;
|
||||
#ifdef INT_MAX
|
||||
if(numfd > (size_t)INT_MAX) {
|
||||
log_err("num_ports exceeds INT_MAX");
|
||||
return 0;
|
||||
}
|
||||
#endif
|
||||
#ifndef DISABLE_EXPLICIT_PORT_RANDOMISATION
|
||||
pif->shpif = shared_ports_find_if(shp, &pif->addr, pif->addrlen,
|
||||
pif->pfxlen);
|
||||
#else
|
||||
(void)shp;
|
||||
#endif
|
||||
pif->maxout = (int)numfd;
|
||||
pif->inuse = 0;
|
||||
pif->out = (struct port_comm**)calloc(numfd,
|
||||
@@ -1720,12 +1727,12 @@ struct outside_network*
|
||||
outside_network_create(struct comm_base *base, size_t bufsize,
|
||||
size_t num_ports, char** ifs, int num_ifs, int do_ip4,
|
||||
int do_ip6, size_t num_tcp, int dscp, struct infra_cache* infra,
|
||||
struct ub_randstate* rnd, int use_caps_for_id, int* availports,
|
||||
int numavailports, size_t unwanted_threshold, int tcp_mss,
|
||||
struct ub_randstate* rnd, int use_caps_for_id,
|
||||
size_t unwanted_threshold, int tcp_mss,
|
||||
void (*unwanted_action)(void*), void* unwanted_param, int do_udp,
|
||||
void* sslctx, int delayclose, int tls_use_sni, struct dt_env* dtenv,
|
||||
int udp_connect, int max_reuse_tcp_queries, int tcp_reuse_timeout,
|
||||
int tcp_auth_query_timeout)
|
||||
int tcp_auth_query_timeout, struct shared_ports* shared_ports)
|
||||
{
|
||||
struct outside_network* outnet = (struct outside_network*)
|
||||
calloc(1, sizeof(struct outside_network));
|
||||
@@ -1760,6 +1767,7 @@ outside_network_create(struct comm_base *base, size_t bufsize,
|
||||
outnet->do_udp = do_udp;
|
||||
outnet->tcp_mss = tcp_mss;
|
||||
outnet->ip_dscp = dscp;
|
||||
outnet->shared_ports = shared_ports;
|
||||
#ifndef S_SPLINT_S
|
||||
if(delayclose) {
|
||||
outnet->delayclose = 1;
|
||||
@@ -1770,11 +1778,18 @@ outside_network_create(struct comm_base *base, size_t bufsize,
|
||||
if(udp_connect) {
|
||||
outnet->udp_connect = 1;
|
||||
}
|
||||
if(numavailports == 0 || num_ports == 0) {
|
||||
if(num_ports == 0) {
|
||||
log_err("no outgoing ports available");
|
||||
outside_network_delete(outnet);
|
||||
return NULL;
|
||||
}
|
||||
#ifdef INT_MAX
|
||||
if(num_ports > (size_t)INT_MAX) {
|
||||
log_err("outgoing num_ports exceeds INT_MAX");
|
||||
outside_network_delete(outnet);
|
||||
return NULL;
|
||||
}
|
||||
#endif
|
||||
#ifndef INET6
|
||||
do_ip6 = 0;
|
||||
#endif
|
||||
@@ -1831,13 +1846,13 @@ outside_network_create(struct comm_base *base, size_t bufsize,
|
||||
/* allocate interfaces */
|
||||
if(num_ifs == 0) {
|
||||
if(do_ip4 && !setup_if(&outnet->ip4_ifs[0], "0.0.0.0",
|
||||
availports, numavailports, num_ports)) {
|
||||
num_ports, outnet->shared_ports)) {
|
||||
log_err("malloc failed");
|
||||
outside_network_delete(outnet);
|
||||
return NULL;
|
||||
}
|
||||
if(do_ip6 && !setup_if(&outnet->ip6_ifs[0], "::",
|
||||
availports, numavailports, num_ports)) {
|
||||
num_ports, outnet->shared_ports)) {
|
||||
log_err("malloc failed");
|
||||
outside_network_delete(outnet);
|
||||
return NULL;
|
||||
@@ -1848,7 +1863,7 @@ outside_network_create(struct comm_base *base, size_t bufsize,
|
||||
for(i=0; i<num_ifs; i++) {
|
||||
if(str_is_ip6(ifs[i]) && do_ip6) {
|
||||
if(!setup_if(&outnet->ip6_ifs[done_6], ifs[i],
|
||||
availports, numavailports, num_ports)){
|
||||
num_ports, outnet->shared_ports)){
|
||||
log_err("malloc failed");
|
||||
outside_network_delete(outnet);
|
||||
return NULL;
|
||||
@@ -1857,7 +1872,7 @@ outside_network_create(struct comm_base *base, size_t bufsize,
|
||||
}
|
||||
if(!str_is_ip6(ifs[i]) && do_ip4) {
|
||||
if(!setup_if(&outnet->ip4_ifs[done_4], ifs[i],
|
||||
availports, numavailports, num_ports)){
|
||||
num_ports, outnet->shared_ports)){
|
||||
log_err("malloc failed");
|
||||
outside_network_delete(outnet);
|
||||
return NULL;
|
||||
@@ -1935,9 +1950,6 @@ outside_network_delete(struct outside_network* outnet)
|
||||
comm_point_delete(pc->cp);
|
||||
free(pc);
|
||||
}
|
||||
#ifndef DISABLE_EXPLICIT_PORT_RANDOMISATION
|
||||
free(outnet->ip4_ifs[i].avail_ports);
|
||||
#endif
|
||||
free(outnet->ip4_ifs[i].out);
|
||||
}
|
||||
free(outnet->ip4_ifs);
|
||||
@@ -1951,9 +1963,6 @@ outside_network_delete(struct outside_network* outnet)
|
||||
comm_point_delete(pc->cp);
|
||||
free(pc);
|
||||
}
|
||||
#ifndef DISABLE_EXPLICIT_PORT_RANDOMISATION
|
||||
free(outnet->ip6_ifs[i].avail_ports);
|
||||
#endif
|
||||
free(outnet->ip6_ifs[i].out);
|
||||
}
|
||||
free(outnet->ip6_ifs);
|
||||
@@ -2163,7 +2172,10 @@ static int
|
||||
select_ifport(struct outside_network* outnet, struct pending* pend,
|
||||
int num_if, struct port_if* ifs)
|
||||
{
|
||||
int my_if, my_port, fd, portno, inuse, tries=0;
|
||||
int my_if, fd, portno, inuse, tries=0;
|
||||
#ifndef DISABLE_EXPLICIT_PORT_RANDOMISATION
|
||||
int reused;
|
||||
#endif
|
||||
struct port_if* pif;
|
||||
/* randomly select interface and port */
|
||||
if(num_if == 0) {
|
||||
@@ -2177,37 +2189,35 @@ select_ifport(struct outside_network* outnet, struct pending* pend,
|
||||
my_if = ub_random_max(outnet->rnd, num_if);
|
||||
pif = &ifs[my_if];
|
||||
#ifndef DISABLE_EXPLICIT_PORT_RANDOMISATION
|
||||
if(outnet->udp_connect) {
|
||||
/* if we connect() we cannot reuse fds for a port */
|
||||
if(pif->inuse >= pif->avail_total) {
|
||||
tries++;
|
||||
if(tries < MAX_PORT_RETRY)
|
||||
continue;
|
||||
log_err("failed to find an open port, drop msg");
|
||||
return 0;
|
||||
}
|
||||
my_port = pif->inuse + ub_random_max(outnet->rnd,
|
||||
pif->avail_total - pif->inuse);
|
||||
} else {
|
||||
my_port = ub_random_max(outnet->rnd, pif->avail_total);
|
||||
if(my_port < pif->inuse) {
|
||||
/* port already open */
|
||||
pend->pc = pif->out[my_port];
|
||||
verbose(VERB_ALGO, "using UDP if=%d port=%d",
|
||||
my_if, pend->pc->number);
|
||||
break;
|
||||
}
|
||||
if(!shared_ports_fetch_random(outnet->shared_ports,
|
||||
pif->shpif, outnet->rnd, outnet->udp_connect,
|
||||
pif->inuse, &portno, &reused)) {
|
||||
tries++;
|
||||
if(tries < MAX_PORT_RETRY)
|
||||
continue;
|
||||
log_err("failed to find an open port, drop msg");
|
||||
return 0;
|
||||
}
|
||||
if(reused) {
|
||||
/* port already open */
|
||||
log_assert(portno < pif->inuse);
|
||||
pend->pc = pif->out[portno];
|
||||
verbose(VERB_ALGO, "using UDP if=%d port=%d",
|
||||
my_if, pend->pc->number);
|
||||
break;
|
||||
}
|
||||
/* try to open new port, if fails, loop to try again */
|
||||
log_assert(pif->inuse < pif->maxout);
|
||||
portno = pif->avail_ports[my_port - pif->inuse];
|
||||
#else
|
||||
my_port = portno = 0;
|
||||
portno = 0;
|
||||
#endif
|
||||
/* try to open new port, if fails, loop to try again */
|
||||
fd = udp_sockport(&pif->addr, pif->addrlen, pif->pfxlen,
|
||||
portno, &inuse, outnet->rnd, outnet->ip_dscp);
|
||||
if(fd == -1 && !inuse) {
|
||||
/* nonrecoverable error making socket */
|
||||
#ifndef DISABLE_EXPLICIT_PORT_RANDOMISATION
|
||||
shared_ports_return_port(outnet->shared_ports,
|
||||
pif->shpif, portno);
|
||||
#endif
|
||||
return 0;
|
||||
}
|
||||
if(fd != -1) {
|
||||
@@ -2224,6 +2234,11 @@ select_ifport(struct outside_network* outnet, struct pending* pend,
|
||||
pend->addrlen);
|
||||
}
|
||||
sock_close(fd);
|
||||
#ifndef DISABLE_EXPLICIT_PORT_RANDOMISATION
|
||||
shared_ports_return_port(
|
||||
outnet->shared_ports,
|
||||
pif->shpif, portno);
|
||||
#endif
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
@@ -2241,14 +2256,14 @@ select_ifport(struct outside_network* outnet, struct pending* pend,
|
||||
|
||||
/* grab port in interface */
|
||||
pif->out[pif->inuse] = pend->pc;
|
||||
#ifndef DISABLE_EXPLICIT_PORT_RANDOMISATION
|
||||
pif->avail_ports[my_port - pif->inuse] =
|
||||
pif->avail_ports[pif->avail_total-pif->inuse-1];
|
||||
#endif
|
||||
pif->inuse++;
|
||||
break;
|
||||
}
|
||||
/* failed, already in use */
|
||||
#ifndef DISABLE_EXPLICIT_PORT_RANDOMISATION
|
||||
shared_ports_return_port(outnet->shared_ports, pif->shpif,
|
||||
portno);
|
||||
#endif
|
||||
verbose(VERB_QUERY, "port %d in use, trying another", portno);
|
||||
tries++;
|
||||
if(tries == MAX_PORT_RETRY) {
|
||||
@@ -2540,7 +2555,16 @@ pending_tcp_query(struct serviced_query* sq, sldns_buffer* packet,
|
||||
w->cb = callback;
|
||||
w->cb_arg = callback_arg;
|
||||
w->ssl_upstream = sq->ssl_upstream;
|
||||
w->tls_auth_name = sq->tls_auth_name;
|
||||
if(sq->tls_auth_name) {
|
||||
w->tls_auth_name = strdup(sq->tls_auth_name);
|
||||
if(!w->tls_auth_name) {
|
||||
comm_timer_delete(w->timer);
|
||||
free(w);
|
||||
return NULL;
|
||||
}
|
||||
} else {
|
||||
w->tls_auth_name = NULL;
|
||||
}
|
||||
w->timeout = timeout;
|
||||
w->id_node.key = NULL;
|
||||
w->write_wait_prev = NULL;
|
||||
@@ -3338,9 +3362,9 @@ serviced_udp_callback(struct comm_point* c, void* arg, int error,
|
||||
if(error == NETEVENT_TIMEOUT) {
|
||||
if(sq->status == serviced_query_UDP_EDNS && sq->last_rtt < 5000 &&
|
||||
(serviced_query_udp_size(sq, serviced_query_UDP_EDNS_FRAG) < serviced_query_udp_size(sq, serviced_query_UDP_EDNS))) {
|
||||
/* fallback to 1480/1280 */
|
||||
/* fallback to 1472/1232 */
|
||||
sq->status = serviced_query_UDP_EDNS_FRAG;
|
||||
log_name_addr(VERB_ALGO, "try edns1xx0", sq->qbuf+10,
|
||||
log_name_addr(VERB_ALGO, "try edns1xx2", sq->qbuf+10,
|
||||
&sq->addr, sq->addrlen);
|
||||
if(!serviced_udp_send(sq, c->buffer)) {
|
||||
serviced_callbacks(sq, NETEVENT_CLOSED, c, rep);
|
||||
@@ -3477,7 +3501,8 @@ outnet_serviced_query(struct outside_network* outnet,
|
||||
char* tls_auth_name, struct sockaddr_storage* addr, socklen_t addrlen,
|
||||
uint8_t* zone, size_t zonelen, struct module_qstate* qstate,
|
||||
comm_point_callback_type* callback, void* callback_arg,
|
||||
sldns_buffer* buff, struct module_env* env, int* was_ratelimited)
|
||||
sldns_buffer* buff, struct module_env* env, int* was_ratelimited,
|
||||
int* ratelimit_incremented)
|
||||
{
|
||||
struct serviced_query* sq;
|
||||
struct service_callback* cb;
|
||||
@@ -3549,6 +3574,7 @@ outnet_serviced_query(struct outside_network* outnet,
|
||||
"delegation point", zone,
|
||||
LDNS_RR_TYPE_NS, LDNS_RR_CLASS_IN);
|
||||
}
|
||||
*ratelimit_incremented = 1;
|
||||
}
|
||||
/* make new serviced query entry */
|
||||
sq = serviced_create(outnet, buff, dnssec, want_dnssec, nocaps,
|
||||
@@ -3630,13 +3656,16 @@ fd_for_dest(struct outside_network* outnet, struct sockaddr_storage* to_addr,
|
||||
{
|
||||
struct sockaddr_storage* addr;
|
||||
socklen_t addrlen;
|
||||
int i, try, pnum, dscp;
|
||||
int i, try, dscp;
|
||||
struct port_if* pif;
|
||||
|
||||
/* create fd */
|
||||
dscp = outnet->ip_dscp;
|
||||
for(try = 0; try<1000; try++) {
|
||||
int port = 0;
|
||||
#ifndef DISABLE_EXPLICIT_PORT_RANDOMISATION
|
||||
int reused = 0;
|
||||
#endif
|
||||
int freebind = 0;
|
||||
int noproto = 0;
|
||||
int inuse = 0;
|
||||
@@ -3665,16 +3694,18 @@ fd_for_dest(struct outside_network* outnet, struct sockaddr_storage* to_addr,
|
||||
addr = &pif->addr;
|
||||
addrlen = pif->addrlen;
|
||||
#ifndef DISABLE_EXPLICIT_PORT_RANDOMISATION
|
||||
pnum = ub_random_max(outnet->rnd, pif->avail_total);
|
||||
if(pnum < pif->inuse) {
|
||||
/* port already open */
|
||||
port = pif->out[pnum]->number;
|
||||
} else {
|
||||
/* unused ports in start part of array */
|
||||
port = pif->avail_ports[pnum - pif->inuse];
|
||||
if(!shared_ports_fetch_random(outnet->shared_ports,
|
||||
pif->shpif, outnet->rnd, 0, pif->inuse,
|
||||
&port, &reused)) {
|
||||
/* try again, perhaps another interface. */
|
||||
continue;
|
||||
}
|
||||
if(reused) {
|
||||
log_assert(port < pif->inuse);
|
||||
port = pif->out[port]->number;
|
||||
}
|
||||
#else
|
||||
pnum = port = 0;
|
||||
port = 0;
|
||||
#endif
|
||||
if(addr_is_ip6(to_addr, to_addrlen)) {
|
||||
struct sockaddr_in6 sa = *(struct sockaddr_in6*)addr;
|
||||
@@ -3689,6 +3720,14 @@ fd_for_dest(struct outside_network* outnet, struct sockaddr_storage* to_addr,
|
||||
(struct sockaddr*)addr, addrlen, 1, &inuse, &noproto,
|
||||
0, 0, 0, NULL, 0, freebind, 0, dscp);
|
||||
}
|
||||
#ifndef DISABLE_EXPLICIT_PORT_RANDOMISATION
|
||||
if(!reused) {
|
||||
/* Return the port to the pool, since the caller does
|
||||
* not keep track of it, also have done fd, and bind. */
|
||||
shared_ports_return_port(outnet->shared_ports,
|
||||
pif->shpif, port);
|
||||
}
|
||||
#endif
|
||||
if(fd != -1) {
|
||||
return fd;
|
||||
}
|
||||
@@ -3741,7 +3780,33 @@ setup_comm_ssl(struct comm_point* cp, struct outside_network* outnet,
|
||||
(void)SSL_set_tlsext_host_name(cp->ssl, host);
|
||||
}
|
||||
#endif
|
||||
#ifdef HAVE_SSL_SET1_HOST
|
||||
#ifdef HAVE_SSL_SET1_DNSNAME
|
||||
if((SSL_CTX_get_verify_mode(outnet->sslctx)&SSL_VERIFY_PEER)) {
|
||||
/* because we set SSL_VERIFY_PEER, in netevent in
|
||||
* ssl_handshake, it'll check if the certificate
|
||||
* verification has succeeded */
|
||||
/* SSL_VERIFY_PEER is set on the sslctx */
|
||||
/* and the certificates to verify with are loaded into
|
||||
* it with SSL_load_verify_locations or
|
||||
* SSL_CTX_set_default_verify_paths */
|
||||
/* setting the hostname makes openssl verify the
|
||||
* host name in the x509 certificate in the
|
||||
* SSL connection*/
|
||||
struct sockaddr_storage tmpaddr;
|
||||
socklen_t tmpaddrlen = (socklen_t)sizeof(tmpaddr);
|
||||
if(ipstrtoaddr(host, UNBOUND_DNS_PORT, &tmpaddr, &tmpaddrlen)) {
|
||||
if(!SSL_set1_ipaddr(cp->ssl, host)) {
|
||||
log_err("SSL_set1_ipaddr failed");
|
||||
return 0;
|
||||
}
|
||||
} else {
|
||||
if(!SSL_set1_dnsname(cp->ssl, host)) {
|
||||
log_err("SSL_set1_dnsname failed");
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
#elif defined(HAVE_SSL_SET1_HOST)
|
||||
if((SSL_CTX_get_verify_mode(outnet->sslctx)&SSL_VERIFY_PEER)) {
|
||||
/* because we set SSL_VERIFY_PEER, in netevent in
|
||||
* ssl_handshake, it'll check if the certificate
|
||||
@@ -3870,7 +3935,8 @@ outnet_comm_point_for_http(struct outside_network* outnet,
|
||||
/* outnet_tcp_connect has closed fd on error for us */
|
||||
return 0;
|
||||
}
|
||||
cp = comm_point_create_http_out(outnet->base, 65552, cb, cb_arg,
|
||||
cp = comm_point_create_http_out(outnet->base,
|
||||
sldns_buffer_capacity(outnet->udp_buff), cb, cb_arg,
|
||||
outnet->udp_buff);
|
||||
if(!cp) {
|
||||
log_err("malloc failure");
|
||||
@@ -3919,11 +3985,7 @@ if_get_mem(struct port_if* pif)
|
||||
{
|
||||
size_t s;
|
||||
int i;
|
||||
s = sizeof(*pif) +
|
||||
#ifndef DISABLE_EXPLICIT_PORT_RANDOMISATION
|
||||
sizeof(int)*pif->avail_total +
|
||||
#endif
|
||||
sizeof(struct port_comm*)*pif->maxout;
|
||||
s = sizeof(*pif) + sizeof(struct port_comm*)*pif->maxout;
|
||||
for(i=0; i<pif->inuse; i++)
|
||||
s += sizeof(*pif->out[i]) +
|
||||
comm_point_get_mem(pif->out[i]->cp);
|
||||
@@ -4011,3 +4073,250 @@ serviced_get_mem(struct serviced_query* sq)
|
||||
return s;
|
||||
}
|
||||
|
||||
#ifndef DISABLE_EXPLICIT_PORT_RANDOMISATION
|
||||
/** Setup shared port interface */
|
||||
static int shared_ports_setup_if(struct shared_ports_if* shpif, char* str,
|
||||
int* availports, int numavailports)
|
||||
{
|
||||
shpif->avail_ports = (int*)memdup(availports,
|
||||
(size_t)numavailports*sizeof(int));
|
||||
if(!shpif->avail_ports)
|
||||
return 0;
|
||||
shpif->avail_total = numavailports;
|
||||
shpif->inuse = 0;
|
||||
shpif->pfxlen = 0;
|
||||
if(!ipstrtoaddr(str, UNBOUND_DNS_PORT, &shpif->addr, &shpif->addrlen) &&
|
||||
!netblockstrtoaddr(str, UNBOUND_DNS_PORT, &shpif->addr,
|
||||
&shpif->addrlen, &shpif->pfxlen))
|
||||
return 0;
|
||||
return 1;
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifndef DISABLE_EXPLICIT_PORT_RANDOMISATION
|
||||
/** Allocate shared ports interfaces */
|
||||
static int shared_ports_alloc_ifs(struct shared_ports* shp, char** ifs,
|
||||
int num_ifs, int do_ip4, int do_ip6, int* availports,
|
||||
int numavailports)
|
||||
{
|
||||
#ifndef INET6
|
||||
do_ip6 = 0;
|
||||
#endif
|
||||
calc_num46(ifs, num_ifs, do_ip4, do_ip6,
|
||||
&shp->num_ip4, &shp->num_ip6);
|
||||
if(shp->num_ip4 != 0) {
|
||||
if(!(shp->ip4_ifs = (struct shared_ports_if*)calloc(
|
||||
(size_t)shp->num_ip4,
|
||||
sizeof(struct shared_ports_if))))
|
||||
return 0;
|
||||
}
|
||||
if(shp->num_ip6 != 0) {
|
||||
if(!(shp->ip6_ifs = (struct shared_ports_if*)calloc(
|
||||
(size_t)shp->num_ip6,
|
||||
sizeof(struct shared_ports_if))))
|
||||
return 0;
|
||||
}
|
||||
if(num_ifs == 0) {
|
||||
if(do_ip4 && !shared_ports_setup_if(&shp->ip4_ifs[0],
|
||||
"0.0.0.0", availports, numavailports))
|
||||
return 0;
|
||||
if(do_ip6 && !shared_ports_setup_if(&shp->ip6_ifs[0],
|
||||
"::", availports, numavailports))
|
||||
return 0;
|
||||
} else {
|
||||
size_t done_4 = 0, done_6 = 0;
|
||||
int i;
|
||||
for(i=0; i<num_ifs; i++) {
|
||||
if(str_is_ip6(ifs[i]) && do_ip6 &&
|
||||
(int)done_6 < shp->num_ip6) {
|
||||
if(!shared_ports_setup_if(&shp->ip6_ifs[done_6],
|
||||
ifs[i], availports, numavailports))
|
||||
return 0;
|
||||
done_6++;
|
||||
}
|
||||
if(!str_is_ip6(ifs[i]) && do_ip4 &&
|
||||
(int)done_4 < shp->num_ip4) {
|
||||
if(!shared_ports_setup_if(&shp->ip4_ifs[done_4],
|
||||
ifs[i], availports, numavailports))
|
||||
return 0;
|
||||
done_4++;
|
||||
}
|
||||
}
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
#endif
|
||||
|
||||
struct shared_ports* shared_ports_create(char** ifs, int num_ifs, int do_ip4,
|
||||
int do_ip6, int* availports, int numavailports)
|
||||
{
|
||||
struct shared_ports* shp = calloc(1, sizeof(*shp));
|
||||
if(!shp) {
|
||||
log_err("malloc failed");
|
||||
return NULL;
|
||||
}
|
||||
lock_basic_init(&shp->lock);
|
||||
lock_protect(&shp->lock, &shp->ip4_ifs, sizeof(shp->ip4_ifs));
|
||||
lock_protect(&shp->lock, &shp->num_ip4, sizeof(shp->num_ip4));
|
||||
lock_protect(&shp->lock, &shp->ip6_ifs, sizeof(shp->ip6_ifs));
|
||||
lock_protect(&shp->lock, &shp->num_ip6, sizeof(shp->num_ip6));
|
||||
|
||||
#ifndef DISABLE_EXPLICIT_PORT_RANDOMISATION
|
||||
/* Allocate interfaces */
|
||||
lock_basic_lock(&shp->lock);
|
||||
if(!shared_ports_alloc_ifs(shp, ifs, num_ifs, do_ip4, do_ip6,
|
||||
availports, numavailports)) {
|
||||
log_err("malloc failed");
|
||||
shared_ports_delete(shp);
|
||||
return NULL;
|
||||
}
|
||||
lock_basic_unlock(&shp->lock);
|
||||
#else
|
||||
(void)ifs; (void)num_ifs; (void)do_ip4; (void)do_ip6;
|
||||
(void)availports; (void)numavailports;
|
||||
#endif
|
||||
return shp;
|
||||
}
|
||||
|
||||
#ifndef DISABLE_EXPLICIT_PORT_RANDOMISATION
|
||||
/** Delete shared ports interface structure */
|
||||
static void shared_ports_if_delete(struct shared_ports_if* shpif)
|
||||
{
|
||||
if(!shpif)
|
||||
return;
|
||||
free(shpif->avail_ports);
|
||||
}
|
||||
#endif
|
||||
|
||||
void shared_ports_delete(struct shared_ports* shp)
|
||||
{
|
||||
#ifndef DISABLE_EXPLICIT_PORT_RANDOMISATION
|
||||
int i;
|
||||
#endif
|
||||
if(!shp)
|
||||
return;
|
||||
lock_basic_destroy(&shp->lock);
|
||||
#ifndef DISABLE_EXPLICIT_PORT_RANDOMISATION
|
||||
for(i=0; i<shp->num_ip4; i++) {
|
||||
shared_ports_if_delete(&shp->ip4_ifs[i]);
|
||||
}
|
||||
free(shp->ip4_ifs);
|
||||
for(i=0; i<shp->num_ip6; i++) {
|
||||
shared_ports_if_delete(&shp->ip6_ifs[i]);
|
||||
}
|
||||
free(shp->ip6_ifs);
|
||||
#endif
|
||||
free(shp);
|
||||
}
|
||||
|
||||
struct shared_ports_if* shared_ports_find_if(struct shared_ports* shp,
|
||||
struct sockaddr_storage* addr, socklen_t addrlen, int pfxlen)
|
||||
{
|
||||
#ifndef DISABLE_EXPLICIT_PORT_RANDOMISATION
|
||||
struct shared_ports_if* ret, *ifs = NULL;
|
||||
int i, num_ifs = 0;
|
||||
lock_basic_lock(&shp->lock);
|
||||
if(addr_is_ip6(addr, addrlen)) {
|
||||
ifs = shp->ip6_ifs;
|
||||
num_ifs = shp->num_ip6;
|
||||
} else {
|
||||
ifs = shp->ip4_ifs;
|
||||
num_ifs = shp->num_ip4;
|
||||
}
|
||||
for(i=0; i<num_ifs; i++) {
|
||||
if(sockaddr_cmp(addr, addrlen, &ifs[i].addr,
|
||||
ifs[i].addrlen) == 0
|
||||
&& pfxlen == ifs[i].pfxlen) {
|
||||
ret = &ifs[i];
|
||||
lock_basic_unlock(&shp->lock);
|
||||
return ret;
|
||||
}
|
||||
}
|
||||
lock_basic_unlock(&shp->lock);
|
||||
return NULL;
|
||||
#else
|
||||
(void)shp; (void)addr; (void)addrlen; (void)pfxlen;
|
||||
return NULL;
|
||||
#endif
|
||||
}
|
||||
|
||||
int shared_ports_fetch_random(struct shared_ports* shp,
|
||||
struct shared_ports_if* shpif, struct ub_randstate* rnd,
|
||||
int udp_connect, int reusenum, int* port, int* reused)
|
||||
{
|
||||
#ifndef DISABLE_EXPLICIT_PORT_RANDOMISATION
|
||||
int portno = 0, my_port = 0;
|
||||
if(!shpif)
|
||||
return 0;
|
||||
# ifdef THREADS_DISABLED
|
||||
(void)shp;
|
||||
# endif
|
||||
lock_basic_lock(&shp->lock);
|
||||
if(udp_connect) {
|
||||
/* if we connect() we cannot reuse fds for a port. */
|
||||
if(shpif->inuse >= shpif->avail_total) {
|
||||
lock_basic_unlock(&shp->lock);
|
||||
return 0;
|
||||
}
|
||||
my_port = ub_random_max(rnd,
|
||||
shpif->avail_total - shpif->inuse);
|
||||
} else {
|
||||
/* select from free ports and open ports on this thread. */
|
||||
if(shpif->inuse >= shpif->avail_total) {
|
||||
lock_basic_unlock(&shp->lock);
|
||||
if(reusenum == 0) {
|
||||
return 0;
|
||||
}
|
||||
my_port = ub_random_max(rnd, reusenum);
|
||||
*port = my_port;
|
||||
*reused = 1;
|
||||
return 1;
|
||||
}
|
||||
my_port = ub_random_max(rnd, shpif->avail_total - shpif->inuse
|
||||
+ reusenum);
|
||||
if(my_port < reusenum) {
|
||||
/* port already open */
|
||||
lock_basic_unlock(&shp->lock);
|
||||
*port = my_port;
|
||||
*reused = 1;
|
||||
return 1;
|
||||
}
|
||||
my_port -= reusenum;
|
||||
}
|
||||
log_assert(shpif->inuse < shpif->avail_total);
|
||||
log_assert(my_port >= 0 && my_port < shpif->avail_total);
|
||||
portno = shpif->avail_ports[my_port];
|
||||
shpif->avail_ports[my_port] =
|
||||
shpif->avail_ports[shpif->avail_total-shpif->inuse-1];
|
||||
shpif->inuse++;
|
||||
lock_basic_unlock(&shp->lock);
|
||||
*port = portno;
|
||||
*reused = 0;
|
||||
return 1;
|
||||
#else
|
||||
(void)shp; (void)shpif; (void)rnd; (void)udp_connect;
|
||||
(void)reusenum;
|
||||
*port = 0;
|
||||
*reused = 0;
|
||||
return 1;
|
||||
#endif
|
||||
}
|
||||
|
||||
void shared_ports_return_port(struct shared_ports* shp,
|
||||
struct shared_ports_if* shpif, int port)
|
||||
{
|
||||
#ifndef DISABLE_EXPLICIT_PORT_RANDOMISATION
|
||||
if(!shpif)
|
||||
return;
|
||||
# ifdef THREADS_DISABLED
|
||||
(void)shp;
|
||||
# endif
|
||||
lock_basic_lock(&shp->lock);
|
||||
log_assert(shpif->inuse > 0);
|
||||
shpif->avail_ports[shpif->avail_total - shpif->inuse] = port;
|
||||
shpif->inuse--;
|
||||
lock_basic_unlock(&shp->lock);
|
||||
#else
|
||||
(void)shp; (void)shpif; (void)port;
|
||||
#endif
|
||||
}
|
||||
|
||||
+101
-13
@@ -70,6 +70,8 @@ struct module_env;
|
||||
struct module_qstate;
|
||||
struct query_info;
|
||||
struct config_file;
|
||||
struct shared_ports;
|
||||
struct shared_ports_if;
|
||||
|
||||
/**
|
||||
* Send queries to outside servers and wait for answers from servers.
|
||||
@@ -119,6 +121,9 @@ struct outside_network {
|
||||
int udp_connect;
|
||||
/** number of udp packets sent. */
|
||||
size_t num_udp_outgoing;
|
||||
/** the shared ports structure, with random ports numbers.
|
||||
* This is a reference to the member in the daemon structure. */
|
||||
struct shared_ports* shared_ports;
|
||||
|
||||
/** array of outgoing IP4 interfaces */
|
||||
struct port_if* ip4_ifs;
|
||||
@@ -211,11 +216,8 @@ struct port_if {
|
||||
int pfxlen;
|
||||
|
||||
#ifndef DISABLE_EXPLICIT_PORT_RANDOMISATION
|
||||
/** the available ports array. These are unused.
|
||||
* Only the first total-inuse part is filled. */
|
||||
int* avail_ports;
|
||||
/** the total number of available ports (size of the array) */
|
||||
int avail_total;
|
||||
/** the shared port numbers for this interface. */
|
||||
struct shared_ports_if* shpif;
|
||||
#endif
|
||||
|
||||
/** array of the commpoints currently in use.
|
||||
@@ -245,6 +247,42 @@ struct port_comm {
|
||||
struct comm_point* cp;
|
||||
};
|
||||
|
||||
/**
|
||||
* Shared ports, the list of ports shared across threads
|
||||
*/
|
||||
struct shared_ports {
|
||||
/** mutex on the ports */
|
||||
lock_basic_type lock;
|
||||
/** array of IP4 interfaces */
|
||||
struct shared_ports_if* ip4_ifs;
|
||||
/** number of outgoing IP4 interfaces */
|
||||
int num_ip4;
|
||||
/** array of IP6 interfaces */
|
||||
struct shared_ports_if* ip6_ifs;
|
||||
/** number of outgoing IP6 interfaces */
|
||||
int num_ip6;
|
||||
};
|
||||
|
||||
/**
|
||||
* Shared ports for an interface.
|
||||
*/
|
||||
struct shared_ports_if {
|
||||
/** address ready to allocate new socket (except port no). */
|
||||
struct sockaddr_storage addr;
|
||||
/** length of addr field */
|
||||
socklen_t addrlen;
|
||||
/** if a netblock, the prefix */
|
||||
int pfxlen;
|
||||
|
||||
/** the available ports array. These are unused.
|
||||
* Only the first total-inuse part is filled. */
|
||||
int* avail_ports;
|
||||
/** the total number of available ports (size of the array) */
|
||||
int avail_total;
|
||||
/** the number in use. */
|
||||
int inuse;
|
||||
};
|
||||
|
||||
/**
|
||||
* Reuse TCP connection, still open can be used again.
|
||||
*/
|
||||
@@ -419,7 +457,7 @@ struct waiting_tcp {
|
||||
void* cb_arg;
|
||||
/** if it uses ssl upstream */
|
||||
int ssl_upstream;
|
||||
/** ref to the tls_auth_name from the serviced_query */
|
||||
/** owned copy of the tls_auth_name (malloced) */
|
||||
char* tls_auth_name;
|
||||
/** the packet was involved in an error, to stop looping errors */
|
||||
int error_count;
|
||||
@@ -500,7 +538,7 @@ struct serviced_query {
|
||||
serviced_query_UDP_EDNS_fallback,
|
||||
/** probe to test TCP noEDNS0 (EDNS gives FORMERRorNOTIMP) */
|
||||
serviced_query_TCP_EDNS_fallback,
|
||||
/** send UDP query with EDNS1480 (or 1280) */
|
||||
/** send UDP query with EDNS1472 (or 1232) */
|
||||
serviced_query_UDP_EDNS_FRAG
|
||||
}
|
||||
/** variable with current status */
|
||||
@@ -551,8 +589,6 @@ struct serviced_query {
|
||||
* @param infra: pointer to infra cached used for serviced queries.
|
||||
* @param rnd: stored to create random numbers for serviced queries.
|
||||
* @param use_caps_for_id: enable to use 0x20 bits to encode id randomness.
|
||||
* @param availports: array of available ports.
|
||||
* @param numavailports: number of available ports in array.
|
||||
* @param unwanted_threshold: when to take defensive action.
|
||||
* @param unwanted_action: the action to take.
|
||||
* @param unwanted_param: user parameter to action.
|
||||
@@ -567,17 +603,18 @@ struct serviced_query {
|
||||
* @param max_reuse_tcp_queries: max number of queries on a reuse connection.
|
||||
* @param tcp_reuse_timeout: timeout for REUSE entries in milliseconds.
|
||||
* @param tcp_auth_query_timeout: timeout in milliseconds for TCP queries to auth servers.
|
||||
* @param shared_ports: the shared_ports structure.
|
||||
* @return: the new structure (with no pending answers) or NULL on error.
|
||||
*/
|
||||
struct outside_network* outside_network_create(struct comm_base* base,
|
||||
size_t bufsize, size_t num_ports, char** ifs, int num_ifs,
|
||||
int do_ip4, int do_ip6, size_t num_tcp, int dscp, struct infra_cache* infra,
|
||||
struct ub_randstate* rnd, int use_caps_for_id, int* availports,
|
||||
int numavailports, size_t unwanted_threshold, int tcp_mss,
|
||||
struct ub_randstate* rnd, int use_caps_for_id,
|
||||
size_t unwanted_threshold, int tcp_mss,
|
||||
void (*unwanted_action)(void*), void* unwanted_param, int do_udp,
|
||||
void* sslctx, int delayclose, int tls_use_sni, struct dt_env *dtenv,
|
||||
int udp_connect, int max_reuse_tcp_queries, int tcp_reuse_timeout,
|
||||
int tcp_auth_query_timeout);
|
||||
int tcp_auth_query_timeout, struct shared_ports* shared_ports);
|
||||
|
||||
/**
|
||||
* Delete outside_network structure.
|
||||
@@ -660,6 +697,8 @@ void pending_delete(struct outside_network* outnet, struct pending* p);
|
||||
* @param env: the module environment.
|
||||
* @param was_ratelimited: it will signal back if the query failed to pass the
|
||||
* ratelimit check.
|
||||
* @param ratelimit_incremented: set to true if the ratelimit counter
|
||||
* was increased.
|
||||
* @return 0 on error, or pointer to serviced query that is used to answer
|
||||
* this serviced query may be shared with other callbacks as well.
|
||||
*/
|
||||
@@ -669,7 +708,8 @@ struct serviced_query* outnet_serviced_query(struct outside_network* outnet,
|
||||
char* tls_auth_name, struct sockaddr_storage* addr, socklen_t addrlen,
|
||||
uint8_t* zone, size_t zonelen, struct module_qstate* qstate,
|
||||
comm_point_callback_type* callback, void* callback_arg,
|
||||
struct sldns_buffer* buff, struct module_env* env, int* was_ratelimited);
|
||||
struct sldns_buffer* buff, struct module_env* env, int* was_ratelimited,
|
||||
int* ratelimit_incremented);
|
||||
|
||||
/**
|
||||
* Remove service query callback.
|
||||
@@ -819,6 +859,54 @@ struct comm_point* outnet_comm_point_for_http(struct outside_network* outnet,
|
||||
/** connect tcp connection to addr, 0 on failure */
|
||||
int outnet_tcp_connect(int s, struct sockaddr_storage* addr, socklen_t addrlen);
|
||||
|
||||
/**
|
||||
* Create new shared ports structure.
|
||||
* @param ifs: interface names (or NULL for default interface).
|
||||
* These interfaces must be able to access all authoritative servers.
|
||||
* @param num_ifs: number of names in array ifs.
|
||||
* @param do_ip4: service IP4.
|
||||
* @param do_ip6: service IP6.
|
||||
* @param availports: array of available ports.
|
||||
* @param numavailports: number of available ports in array.
|
||||
* @return new, or NULL on failure.
|
||||
*/
|
||||
struct shared_ports* shared_ports_create(char** ifs, int num_ifs, int do_ip4,
|
||||
int do_ip6, int* availports, int numavailports);
|
||||
|
||||
/**
|
||||
* Delete shared ports structure.
|
||||
* @param shp: shared ports structure.
|
||||
*/
|
||||
void shared_ports_delete(struct shared_ports* shp);
|
||||
|
||||
/** Find interface in shared ports. */
|
||||
struct shared_ports_if* shared_ports_find_if(struct shared_ports* shp,
|
||||
struct sockaddr_storage* addr, socklen_t addrlen, int pfxlen);
|
||||
|
||||
/**
|
||||
* Get a shared port from the list of random ports.
|
||||
* @param shp: shared ports structure.
|
||||
* @param shpif: the shared ports interface.
|
||||
* @param rnd: used to make random numbers.
|
||||
* @param udp_connect: set to true if no reuse is possible.
|
||||
* @param reusenum: number of ports that can be reused (already open).
|
||||
* @param port: the port number is returned.
|
||||
* @param reused: if the port numer is reused, returned.
|
||||
* @return false on failure. That can mean no more free ports to use.
|
||||
*/
|
||||
int shared_ports_fetch_random(struct shared_ports* shp,
|
||||
struct shared_ports_if* shpif, struct ub_randstate* rnd,
|
||||
int udp_connect, int reusenum, int* port, int* reused);
|
||||
|
||||
/**
|
||||
* Return a shared port to the list of random ports.
|
||||
* @param shp: shared ports structure.
|
||||
* @param shpif: the shared ports interface.
|
||||
* @param port: port number to return to be used again.
|
||||
*/
|
||||
void shared_ports_return_port(struct shared_ports* shp,
|
||||
struct shared_ports_if* shpif, int port);
|
||||
|
||||
/** callback for incoming udp answers from the network */
|
||||
int outnet_udp_cb(struct comm_point* c, void* arg, int error,
|
||||
struct comm_reply *reply_info);
|
||||
|
||||
+112
-50
@@ -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;
|
||||
@@ -721,13 +764,22 @@ rpz_insert_local_zones_trigger(struct local_zones* lz, uint8_t* dname,
|
||||
char* rrstr = sldns_wire2str_rr(rr, rr_len);
|
||||
if(rrstr == NULL) {
|
||||
log_err("malloc error while inserting rpz nsdname trigger");
|
||||
free(dname);
|
||||
if(!newzone)
|
||||
free(dname);
|
||||
lock_rw_unlock(&lz->lock);
|
||||
return;
|
||||
}
|
||||
lock_rw_wrlock(&z->lock);
|
||||
local_zone_enter_rr(z, dname, dnamelen, dnamelabs, rrtype,
|
||||
rrclass, ttl, rdata, rdata_len, rrstr);
|
||||
if(!local_zone_enter_rr(z, dname, dnamelen, dnamelabs, rrtype,
|
||||
rrclass, ttl, rdata, rdata_len, rrstr)) {
|
||||
log_err("rpz: could not enter local-data: %s", rrstr);
|
||||
if(!newzone)
|
||||
free(dname);
|
||||
lock_rw_unlock(&z->lock);
|
||||
lock_rw_unlock(&lz->lock);
|
||||
free(rrstr);
|
||||
return;
|
||||
}
|
||||
lock_rw_unlock(&z->lock);
|
||||
free(rrstr);
|
||||
}
|
||||
@@ -805,8 +857,9 @@ rpz_insert_nsdname_trigger(struct rpz* r, uint8_t* dname, size_t dnamelen,
|
||||
uint8_t* dname_stripped = NULL;
|
||||
size_t dnamelen_stripped = 0;
|
||||
|
||||
rpz_strip_nsdname_suffix(dname, dnamelen, &dname_stripped,
|
||||
&dnamelen_stripped);
|
||||
if(!rpz_strip_nsdname_suffix(dname, dnamelen, &dname_stripped,
|
||||
&dnamelen_stripped))
|
||||
return;
|
||||
if(a == RPZ_INVALID_ACTION) {
|
||||
verbose(VERB_ALGO, "rpz: skipping invalid action");
|
||||
free(dname_stripped);
|
||||
@@ -904,8 +957,8 @@ rpz_report_rrset_error(const char* msg, uint8_t* rr, size_t rr_len) {
|
||||
|
||||
/* from localzone.c; difference is we don't have a dname */
|
||||
static struct local_rrset*
|
||||
rpz_clientip_new_rrset(struct regional* region,
|
||||
struct clientip_synthesized_rr* raddr, uint16_t rrtype, uint16_t rrclass)
|
||||
rpz_clientip_new_rrset(struct regional* region, uint16_t rrtype,
|
||||
uint16_t rrclass)
|
||||
{
|
||||
struct packed_rrset_data* pd;
|
||||
struct local_rrset* rrset = (struct local_rrset*)
|
||||
@@ -914,8 +967,6 @@ rpz_clientip_new_rrset(struct regional* region,
|
||||
log_err("out of memory");
|
||||
return NULL;
|
||||
}
|
||||
rrset->next = raddr->data;
|
||||
raddr->data = rrset;
|
||||
rrset->rrset = (struct ub_packed_rrset_key*)
|
||||
regional_alloc_zero(region, sizeof(*rrset->rrset));
|
||||
if(rrset->rrset == NULL) {
|
||||
@@ -954,12 +1005,18 @@ rpz_clientip_enter_rr(struct regional* region, struct clientip_synthesized_rr* r
|
||||
return 0;
|
||||
}
|
||||
|
||||
rrset = rpz_clientip_new_rrset(region, raddr, rrtype, rrclass);
|
||||
if(raddr->data == NULL) {
|
||||
rrset = rpz_clientip_new_rrset(region, rrtype, rrclass);
|
||||
if(rrset == NULL) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
return rrset_insert_rr(region, rrset->rrset->entry.data, rdata, rdata_len, ttl, "");
|
||||
if(!rrset_insert_rr(region, rrset->rrset->entry.data, rdata, rdata_len, ttl, ""))
|
||||
return 0;
|
||||
|
||||
/* Link in now that the allocations have succeeded. */
|
||||
rrset->next = raddr->data;
|
||||
raddr->data = rrset;
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int
|
||||
@@ -982,7 +1039,6 @@ rpz_clientip_insert_trigger_rr(struct clientip_synthesized_rrset* set, struct so
|
||||
lock_rw_wrlock(&node->lock);
|
||||
lock_rw_unlock(&set->lock);
|
||||
|
||||
node->action = a;
|
||||
if(a == RPZ_LOCAL_DATA_ACTION) {
|
||||
if(!rpz_clientip_enter_rr(set->region, node, rrtype,
|
||||
rrclass, ttl, rdata, rdata_len)) {
|
||||
@@ -992,6 +1048,7 @@ rpz_clientip_insert_trigger_rr(struct clientip_synthesized_rrset* set, struct so
|
||||
}
|
||||
|
||||
}
|
||||
node->action = a;
|
||||
|
||||
lock_rw_unlock(&node->lock);
|
||||
|
||||
@@ -1977,8 +2034,9 @@ rpz_synthesize_nodata(struct rpz* ATTR_UNUSED(r), struct module_qstate* ms,
|
||||
0, /* total */
|
||||
sec_status_insecure,
|
||||
LDNS_EDE_NONE);
|
||||
if(msg->rep)
|
||||
msg->rep->authoritative = 1;
|
||||
if(!msg->rep)
|
||||
return NULL;
|
||||
msg->rep->authoritative = 1;
|
||||
if(!rpz_add_soa(msg->rep, ms, az))
|
||||
return NULL;
|
||||
return msg;
|
||||
@@ -2008,8 +2066,9 @@ rpz_synthesize_nxdomain(struct rpz* r, struct module_qstate* ms,
|
||||
0, /* total */
|
||||
sec_status_insecure,
|
||||
LDNS_EDE_NONE);
|
||||
if(msg->rep)
|
||||
msg->rep->authoritative = 1;
|
||||
if(!msg->rep)
|
||||
return NULL;
|
||||
msg->rep->authoritative = 1;
|
||||
if(!rpz_add_soa(msg->rep, ms, az))
|
||||
return NULL;
|
||||
return msg;
|
||||
@@ -2062,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))
|
||||
@@ -2227,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;
|
||||
@@ -2833,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
|
||||
|
||||
+11
-2
@@ -67,19 +67,28 @@ sldns_rr_dnskey_key_size_raw(const unsigned char* keydata,
|
||||
case LDNS_RSASHA512:
|
||||
#endif
|
||||
if (len > 0) {
|
||||
size_t nlen, offset;
|
||||
if (keydata[0] == 0) {
|
||||
/* big exponent */
|
||||
if (len > 3) {
|
||||
memmove(&int16, keydata + 1, 2);
|
||||
exp = ntohs(int16);
|
||||
return (len - exp - 3)*8;
|
||||
offset = 3;
|
||||
} else {
|
||||
return 0;
|
||||
}
|
||||
} else {
|
||||
exp = keydata[0];
|
||||
return (len-exp-1)*8;
|
||||
offset = 1;
|
||||
}
|
||||
if(exp+offset > len)
|
||||
return 0;
|
||||
nlen = len - exp - offset;
|
||||
/* prefixed zeroes mean a smaller value */
|
||||
while(nlen > 0 &&
|
||||
keydata[len-nlen] == 0)
|
||||
nlen--;
|
||||
return nlen*8;
|
||||
} else {
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
|
||||
+27
-6
@@ -874,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;
|
||||
@@ -1201,7 +1208,7 @@ sldns_str2wire_svcbparam_ipv4hint(const char* val, uint8_t* rd, size_t* rd_len)
|
||||
{
|
||||
size_t count;
|
||||
char ip_str[INET_ADDRSTRLEN+1];
|
||||
char *next_ip_str;
|
||||
const char *next_ip_str;
|
||||
size_t i;
|
||||
|
||||
for (i = 0, count = 1; val[i]; i++) {
|
||||
@@ -1256,7 +1263,7 @@ sldns_str2wire_svcbparam_ipv6hint(const char* val, uint8_t* rd, size_t* rd_len)
|
||||
{
|
||||
size_t count;
|
||||
char ip_str[INET6_ADDRSTRLEN+1];
|
||||
char *next_ip_str;
|
||||
const char *next_ip_str;
|
||||
size_t i;
|
||||
|
||||
for (i = 0, count = 1; val[i]; i++) {
|
||||
@@ -1317,7 +1324,7 @@ static int
|
||||
sldns_str2wire_svcbparam_mandatory(const char* val, uint8_t* rd, size_t* rd_len)
|
||||
{
|
||||
size_t i, count, val_len;
|
||||
char* next_key;
|
||||
const char* next_key;
|
||||
|
||||
val_len = strlen(val);
|
||||
|
||||
@@ -1410,6 +1417,7 @@ sldns_str2wire_svcbparam_ech_value(const char* val, uint8_t* rd, size_t* rd_len)
|
||||
return LDNS_WIREPARSE_ERR_BUFFER_TOO_SMALL;
|
||||
sldns_write_uint16(rd, SVCB_KEY_ECH);
|
||||
sldns_write_uint16(rd + 2, 0);
|
||||
*rd_len = 4;
|
||||
|
||||
return LDNS_WIREPARSE_ERR_OK;
|
||||
}
|
||||
@@ -2302,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 */
|
||||
@@ -2360,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 */
|
||||
@@ -2392,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++;
|
||||
}
|
||||
|
||||
+165
-11
@@ -156,7 +156,7 @@ char* wsa_strerror(int err);
|
||||
#endif
|
||||
|
||||
static const char ICANN_UPDATE_CA[] =
|
||||
/* The ICANN CA fetched at 24 Sep 2010. Valid to 2028 */
|
||||
/* The ICANN CA fetched at 29 May 2026. Valid to 20 Mar 2045 */
|
||||
"-----BEGIN CERTIFICATE-----\n"
|
||||
"MIIDdzCCAl+gAwIBAgIBATANBgkqhkiG9w0BAQsFADBdMQ4wDAYDVQQKEwVJQ0FO\n"
|
||||
"TjEmMCQGA1UECxMdSUNBTk4gQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkxFjAUBgNV\n"
|
||||
@@ -177,6 +177,40 @@ static const char ICANN_UPDATE_CA[] =
|
||||
"15nu5JBSewrCkYqYYmaxyOC3WrVGfHZxVI7MpIFcGdvSb2a1uyuua8l0BKgk3ujF\n"
|
||||
"0/wsHNeP22qNyVO+XVBzrM8fk8BSUFuiT/6tZTYXRtEt5aKQZgXbKU5dUF3jT9qg\n"
|
||||
"j/Br5BZw3X/zd325TvnswzMC1+ljLzHnQGGk\n"
|
||||
"-----END CERTIFICATE-----\n"
|
||||
"\n"
|
||||
"-----BEGIN CERTIFICATE-----\n"
|
||||
"MIIFsTCCA5mgAwIBAgIUQFsYkgroBoe69HKQPy8/DQuiLwgwDQYJKoZIhvcNAQEN\n"
|
||||
"BQAwYDELMAkGA1UEBhMCVVMxDjAMBgNVBAoMBUlDQU5OMSYwJAYDVQQLDB1JQ0FO\n"
|
||||
"TiBDZXJ0aWZpY2F0aW9uIEF1dGhvcml0eTEZMBcGA1UEAwwQSUNBTk4gUm9vdCBD\n"
|
||||
"QSB2MjAeFw0yNTAzMjAyMTA0MjZaFw00NTAzMjAyMTA0MjZaMGAxCzAJBgNVBAYT\n"
|
||||
"AlVTMQ4wDAYDVQQKDAVJQ0FOTjEmMCQGA1UECwwdSUNBTk4gQ2VydGlmaWNhdGlv\n"
|
||||
"biBBdXRob3JpdHkxGTAXBgNVBAMMEElDQU5OIFJvb3QgQ0EgdjIwggIiMA0GCSqG\n"
|
||||
"SIb3DQEBAQUAA4ICDwAwggIKAoICAQCepDjrubjR7en/uZWo7MAnzFIIvUPYEc7b\n"
|
||||
"+AlefdlEDQ1JEmpfrvt/4CX9lJ9ShIBR6zwrQeDvrj5XZ2kEjbJ8Nnc6sM/ojdyr\n"
|
||||
"5jSLqcDPH9fJg7jCW02KF8CtqWsnqcW6jjTIZcCWkg9lEixdF8QAjIEgJtZte+Yh\n"
|
||||
"XeyN0KD2EaO8U5Id0bLvMyphuO1OCGKzDtetcX8K7SvoshdJx3lPIlYzqXl0nVAY\n"
|
||||
"iCeNdeDzTNjEOHYJOP6dYoZI8nKRJltMkZcCCjBE2vQuSMY2w4pOlWk1skHjMWXj\n"
|
||||
"QsZzngXuNG56zialL0TPEDVWjWRjzOnruHUAs4KUY8Zs+Nt8JdSlXMi825PKoKpp\n"
|
||||
"ESs7/ZG1mPjVOYp7Z7ntrRjJFgnUBjWzVPOx4yHiJj1ur+OpqP18oP5YfqY+tKmz\n"
|
||||
"7vlfRGGOEd08a0XgZISDNKpMAovn5pRUHTWPCCjc28tns9ODPvr1cQi+QSwTv+v8\n"
|
||||
"wnA5etGrsead88Rv/ieaq5ikMJTRDfW4d9SY2uPcMGvfU6VdQLRhQkzEVTQNAJ1R\n"
|
||||
"i2lOoJbbjwnK+OU9OhST/OqdjJDJAhTAstdUnrr8WBU80xM75MIaaTjSBCvZ1wro\n"
|
||||
"pAi2hYb0tedTH6WarSW3MH9HcEoGGzs2GD3hDB0a2eCp+TdAs8Up944SjY7UV4Jx\n"
|
||||
"sOC7TxbmkQIDAQABo2MwYTAdBgNVHQ4EFgQU+1EuMRuOZ/ecsfYzNQ+yGZsxZrMw\n"
|
||||
"HwYDVR0jBBgwFoAU+1EuMRuOZ/ecsfYzNQ+yGZsxZrMwDwYDVR0TAQH/BAUwAwEB\n"
|
||||
"/zAOBgNVHQ8BAf8EBAMCAf4wDQYJKoZIhvcNAQENBQADggIBACz38SkKR1WsEZnX\n"
|
||||
"x1BKaS5/oQPw+7quDQCKGoD2Vz7CR7yQh4zQn/Hh0173vKvRWcwN2io0iLJ1ysv5\n"
|
||||
"jXBLeWZh3djiQlXP3iWp4s01SiUwmFssxi3SD1IT2jNosk1xcVWthle9zth7Y8Mp\n"
|
||||
"iUJYnHobP7tX7H2g+I8Rqw2sEX/yPSYMYcdH5a1xRMPOLHTyOaCgevRBBBtXkiAJ\n"
|
||||
"Ob9QKZTaFaXntPXBKNSGkVb2d+2qKyJMrwd0KNI+SVSoIgNDAxkNOdi9x6X6ETW2\n"
|
||||
"4aYFsytohFVkNUXx2eFYRim4yjnD8PHIvDQSofLfSAC5TOERtwUFd+Mw3/di+HCm\n"
|
||||
"50OJPyoxZLjWQCCfNUZzgZZOe+zT6lgBiV3KB0UuuAdq7jGUeH/328HJDi30BvNj\n"
|
||||
"+TNb9Hmpm+ZDguM+f8p7GxapX8AVNu/xErtl4msYiVJrr1qqV+qLLEMwIz0raujG\n"
|
||||
"FFDd6N43wgduffbU20pThry0Y7rku5+RZjUZe/T7ZL+NUKiqXAPufrkqVkjX/8T+\n"
|
||||
"wyNZz8KkiQwkJthojpppa79FDxn/A2M8tt+FQqIONAUPR2m5nurVgftQH0z5ZtDB\n"
|
||||
"YykUlkUiPOJNXoDOIkbpA7lW2wezeY4te+EiSeUZSE541N5QBwaItaonIZsIgn6C\n"
|
||||
"pMnwChV9468oRE20bdqq9+Go7g4E\n"
|
||||
"-----END CERTIFICATE-----\n";
|
||||
|
||||
static const char DS_TRUST_ANCHOR[] =
|
||||
@@ -1674,18 +1708,116 @@ static unsigned long
|
||||
get_usage_of_ex(X509* cert)
|
||||
{
|
||||
unsigned long val = 0;
|
||||
#ifdef HAVE_X509_GET_KEY_USAGE
|
||||
val = X509_get_key_usage(cert);
|
||||
if (val == UINT32_MAX)
|
||||
return 0;
|
||||
#else
|
||||
ASN1_BIT_STRING* s;
|
||||
if((s=X509_get_ext_d2i(cert, NID_key_usage, NULL, NULL))) {
|
||||
if(s->length > 0) {
|
||||
val = s->data[0];
|
||||
if(s->length > 1)
|
||||
val |= s->data[1] << 8;
|
||||
# ifdef HAVE_ASN1_STRING_GET0_DATA
|
||||
const unsigned char *data = ASN1_STRING_get0_data(s);
|
||||
# else
|
||||
const unsigned char *data = ASN1_STRING_data(s);
|
||||
# endif
|
||||
int len = ASN1_STRING_length(s);
|
||||
if(len > 0) {
|
||||
val = data[0];
|
||||
if(len > 1)
|
||||
val |= data[1] << 8;
|
||||
}
|
||||
ASN1_BIT_STRING_free(s);
|
||||
}
|
||||
#endif
|
||||
return val;
|
||||
}
|
||||
|
||||
#if !defined(HAVE_X509_NAME_GET_TEXT_BY_NID) || defined(DEPRECATED_X509_NAME_GET_TEXT_BY_NID)
|
||||
/** print verbose output about name extension data. */
|
||||
static void
|
||||
print_name_ext(
|
||||
#if OPENSSL_VERSION_NUMBER >= 0x40000000
|
||||
const
|
||||
#endif
|
||||
X509_NAME* nm, int nid, const char* str)
|
||||
{
|
||||
int lastpos = -1;
|
||||
for(;;) {
|
||||
#if OPENSSL_VERSION_NUMBER >= 0x40000000
|
||||
const
|
||||
#endif
|
||||
X509_NAME_ENTRY* ne;
|
||||
#if OPENSSL_VERSION_NUMBER >= 0x40000000
|
||||
const
|
||||
#endif
|
||||
ASN1_STRING *asn;
|
||||
const unsigned char *data;
|
||||
char buf[1024];
|
||||
|
||||
lastpos = X509_NAME_get_index_by_NID(nm, nid, lastpos);
|
||||
if(lastpos == -1 || lastpos == -2)
|
||||
break;
|
||||
ne = X509_NAME_get_entry(nm, lastpos);
|
||||
if(!ne) continue;
|
||||
asn = X509_NAME_ENTRY_get_data(ne);
|
||||
if(!asn) continue;
|
||||
# ifdef HAVE_ASN1_STRING_GET0_DATA
|
||||
data = ASN1_STRING_get0_data(asn);
|
||||
# else
|
||||
data = ASN1_STRING_data(asn);
|
||||
# endif
|
||||
if(!data) continue;
|
||||
if(ASN1_STRING_length(asn) > (int)sizeof(buf)-1) continue;
|
||||
memcpy(buf, data, ASN1_STRING_length(asn));
|
||||
buf[ASN1_STRING_length(asn)]=0;
|
||||
printf("%s: %s\n", str, buf);
|
||||
}
|
||||
}
|
||||
#endif /* X509_NAME_GET_TEXT_BY_NID */
|
||||
|
||||
#if !defined(HAVE_X509_NAME_GET_TEXT_BY_NID) || defined(DEPRECATED_X509_NAME_GET_TEXT_BY_NID)
|
||||
/** see if the valid emailaddr is present. */
|
||||
static int
|
||||
has_valid_emailaddr(
|
||||
#if OPENSSL_VERSION_NUMBER >= 0x40000000
|
||||
const
|
||||
#endif
|
||||
X509_NAME* nm, const char* p7signer)
|
||||
{
|
||||
int lastpos = -1;
|
||||
for(;;) {
|
||||
#if OPENSSL_VERSION_NUMBER >= 0x40000000
|
||||
const
|
||||
#endif
|
||||
X509_NAME_ENTRY* ne;
|
||||
#if OPENSSL_VERSION_NUMBER >= 0x40000000
|
||||
const
|
||||
#endif
|
||||
ASN1_STRING *asn;
|
||||
const unsigned char *data;
|
||||
|
||||
lastpos = X509_NAME_get_index_by_NID(nm,
|
||||
NID_pkcs9_emailAddress, lastpos);
|
||||
if(lastpos == -1 || lastpos == -2)
|
||||
break;
|
||||
ne = X509_NAME_get_entry(nm, lastpos);
|
||||
if(!ne) continue;
|
||||
asn = X509_NAME_ENTRY_get_data(ne);
|
||||
if(!asn) continue;
|
||||
# ifdef HAVE_ASN1_STRING_GET0_DATA
|
||||
data = ASN1_STRING_get0_data(asn);
|
||||
# else
|
||||
data = ASN1_STRING_data(asn);
|
||||
# endif
|
||||
if(!data) continue;
|
||||
if(ASN1_STRING_length(asn) == (int)strlen(p7signer) &&
|
||||
strncmp((char*)data, p7signer, strlen(p7signer)) == 0)
|
||||
return 1; /* match */
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
#endif /* X509_NAME_GET_TEXT_BY_NID */
|
||||
|
||||
/** get valid signers from the list of signers in the signature */
|
||||
static STACK_OF(X509)*
|
||||
get_valid_signers(PKCS7* p7, const char* p7signer)
|
||||
@@ -1705,6 +1837,9 @@ get_valid_signers(PKCS7* p7, const char* p7signer)
|
||||
return NULL;
|
||||
}
|
||||
for(i=0; i<sk_X509_num(signers); i++) {
|
||||
#if OPENSSL_VERSION_NUMBER >= 0x40000000
|
||||
const
|
||||
#endif
|
||||
X509_NAME* nm = X509_get_subject_name(
|
||||
sk_X509_value(signers, i));
|
||||
char buf[1024];
|
||||
@@ -1717,17 +1852,29 @@ get_valid_signers(PKCS7* p7, const char* p7signer)
|
||||
(int)sizeof(buf));
|
||||
printf("signer %d: Subject: %s\n", i,
|
||||
nmline?nmline:"no subject");
|
||||
#if !defined(HAVE_X509_NAME_GET_TEXT_BY_NID) || defined(DEPRECATED_X509_NAME_GET_TEXT_BY_NID)
|
||||
if(verb >= 3) {
|
||||
print_name_ext(nm, NID_commonName,
|
||||
"commonName");
|
||||
print_name_ext(nm, NID_pkcs9_emailAddress,
|
||||
"emailAddress");
|
||||
}
|
||||
#else
|
||||
if(verb >= 3 && X509_NAME_get_text_by_NID(nm,
|
||||
NID_commonName, buf, (int)sizeof(buf)))
|
||||
NID_commonName, buf, (int)sizeof(buf)) > 0)
|
||||
printf("commonName: %s\n", buf);
|
||||
if(verb >= 3 && X509_NAME_get_text_by_NID(nm,
|
||||
NID_pkcs9_emailAddress, buf, (int)sizeof(buf)))
|
||||
NID_pkcs9_emailAddress, buf, (int)sizeof(buf)) > 0)
|
||||
printf("emailAddress: %s\n", buf);
|
||||
#endif
|
||||
}
|
||||
if(verb) {
|
||||
int ku_loc = X509_get_ext_by_NID(
|
||||
sk_X509_value(signers, i), NID_key_usage, -1);
|
||||
if(verb >= 3 && ku_loc >= 0) {
|
||||
#if OPENSSL_VERSION_NUMBER >= 0x40000000
|
||||
const
|
||||
#endif
|
||||
X509_EXTENSION *ex = X509_get_ext(
|
||||
sk_X509_value(signers, i), ku_loc);
|
||||
if(ex) {
|
||||
@@ -1741,16 +1888,23 @@ get_valid_signers(PKCS7* p7, const char* p7signer)
|
||||
/* there is no name to check, return all records */
|
||||
if(verb) printf("did not check commonName of signer\n");
|
||||
} else {
|
||||
if(!X509_NAME_get_text_by_NID(nm,
|
||||
#if !defined(HAVE_X509_NAME_GET_TEXT_BY_NID) || defined(DEPRECATED_X509_NAME_GET_TEXT_BY_NID)
|
||||
if(!has_valid_emailaddr(nm, p7signer)) {
|
||||
if(verb) printf("removed cert with wrong emailaddress\n");
|
||||
continue; /* wrong name, skip it */
|
||||
}
|
||||
#else
|
||||
if(X509_NAME_get_text_by_NID(nm,
|
||||
NID_pkcs9_emailAddress,
|
||||
buf, (int)sizeof(buf))) {
|
||||
if(verb) printf("removed cert with no name\n");
|
||||
buf, (int)sizeof(buf)) <= 0) {
|
||||
if(verb) printf("removed cert with no emailaddress\n");
|
||||
continue; /* no name, no use */
|
||||
}
|
||||
if(strcmp(buf, p7signer) != 0) {
|
||||
if(verb) printf("removed cert with wrong name\n");
|
||||
if(verb) printf("removed cert with wrong emailaddress\n");
|
||||
continue; /* wrong name, skip it */
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
/* check that the key usage allows digital signatures
|
||||
|
||||
@@ -73,6 +73,9 @@
|
||||
#ifdef HAVE_GLOB_H
|
||||
#include <glob.h>
|
||||
#endif
|
||||
#ifdef HAVE_FNMATCH_H
|
||||
#include <fnmatch.h>
|
||||
#endif
|
||||
#ifdef WITH_PYTHONMODULE
|
||||
#include "pythonmod/pythonmod.h"
|
||||
#endif
|
||||
@@ -728,6 +731,122 @@ check_modules_exist(const char* module_conf)
|
||||
}
|
||||
}
|
||||
|
||||
#ifdef USE_IPSECMOD
|
||||
/** Compare filename with string, true if it matches the name. */
|
||||
static int
|
||||
file_string_matches(char* str, char* fname, struct config_file* cfg)
|
||||
{
|
||||
char* f;
|
||||
if(!str || str[0] == 0)
|
||||
return 0;
|
||||
/* compare name after chroot and working dir are applied */
|
||||
f = fname_after_chroot(str, cfg, 1);
|
||||
if(!f) fatal_exit("out of memory");
|
||||
if(strcmp(fname, f) == 0) {
|
||||
free(f);
|
||||
return 1;
|
||||
}
|
||||
free(f);
|
||||
return 0;
|
||||
}
|
||||
#endif /* USE_IPSECMOD */
|
||||
|
||||
/** Compare filename with list of files, true if list contains the name. */
|
||||
static int
|
||||
file_list_contains(struct config_strlist* list, char* fname,
|
||||
struct config_file* cfg)
|
||||
{
|
||||
struct config_strlist* s;
|
||||
char* f;
|
||||
for(s = list; s; s = s->next) {
|
||||
if(!s->str || s->str[0] == 0)
|
||||
continue; /* skip if no file name */
|
||||
/* compare names after chroot and working dir are applied */
|
||||
f = fname_after_chroot(s->str, cfg, 1);
|
||||
if(!f) fatal_exit("out of memory");
|
||||
if(strcmp(fname, f) == 0) {
|
||||
free(f);
|
||||
return 1;
|
||||
}
|
||||
free(f);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
/** Compare filename with list of files, true if list contains the name,
|
||||
* with glob compare. */
|
||||
static int
|
||||
file_list_contains_wild(struct config_strlist* list, char* fname,
|
||||
struct config_file* cfg)
|
||||
{
|
||||
struct config_strlist* s;
|
||||
char* f;
|
||||
for(s = list; s; s = s->next) {
|
||||
if(!s->str || s->str[0] == 0)
|
||||
continue; /* skip if no file name */
|
||||
/* compare names after chroot and working dir are applied */
|
||||
f = fname_after_chroot(s->str, cfg, 1);
|
||||
if(!f) fatal_exit("out of memory");
|
||||
if(strcmp(fname, f) == 0) {
|
||||
free(f);
|
||||
return 1;
|
||||
}
|
||||
#ifdef HAVE_FNMATCH
|
||||
if(fnmatch(f, fname, 0) == 0) {
|
||||
log_err("trusted-keys-file: \"%s\" matches zonefile '%s'",
|
||||
s->str, fname);
|
||||
free(f);
|
||||
return 1;
|
||||
}
|
||||
#endif
|
||||
free(f);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
/** Check if the auth-zone/rpz zonefile: conflicts with other files,
|
||||
* so it would overwrite that file. Refuse it aliasing any read-side bootstrap
|
||||
* file. */
|
||||
static void
|
||||
check_file_clobber(struct config_file* cfg)
|
||||
{
|
||||
struct config_auth* p;
|
||||
char* zfile, *sourceopt = NULL;
|
||||
for(p = cfg->auths; p; p = p->next) {
|
||||
if(!p->name || p->name[0] == 0)
|
||||
continue; /* skip if no name */
|
||||
if(!p->zonefile || p->zonefile[0]==0)
|
||||
continue; /* no zone file */
|
||||
zfile = fname_after_chroot(p->zonefile, cfg, 1);
|
||||
if(!zfile) fatal_exit("out of memory");
|
||||
if(file_list_contains(cfg->auto_trust_anchor_file_list, zfile,
|
||||
cfg))
|
||||
sourceopt = "auto-trust-anchor-file";
|
||||
else if(file_list_contains(cfg->trust_anchor_file_list, zfile,
|
||||
cfg))
|
||||
sourceopt = "trust-anchor-file";
|
||||
else if(file_list_contains_wild(cfg->trusted_keys_file_list,
|
||||
zfile, cfg))
|
||||
sourceopt = "trusted-keys-file";
|
||||
else if(file_list_contains(cfg->root_hints, zfile, cfg))
|
||||
sourceopt = "root-hints";
|
||||
else if(file_list_contains(cfg->tls_session_ticket_keys.first,
|
||||
zfile, cfg))
|
||||
sourceopt = "tls-session-ticket-keys";
|
||||
#ifdef USE_IPSECMOD
|
||||
if(cfg->ipsecmod_enabled &&
|
||||
file_string_matches(cfg->ipsecmod_hook, zfile, cfg))
|
||||
sourceopt = "ipsecmod-hook";
|
||||
#endif
|
||||
if(sourceopt)
|
||||
fatal_exit("auth-zone '%s': zonefile \"%s\" "
|
||||
"is the same path as a %s option. "
|
||||
"The auth-zone transfer would overwrite it.",
|
||||
p->name, p->zonefile, sourceopt);
|
||||
free(zfile);
|
||||
}
|
||||
}
|
||||
|
||||
/** check configuration for errors */
|
||||
static void
|
||||
morechecks(struct config_file* cfg)
|
||||
@@ -822,6 +941,7 @@ morechecks(struct config_file* cfg)
|
||||
cfg->chrootdir, cfg);
|
||||
}
|
||||
#endif
|
||||
check_file_clobber(cfg);
|
||||
/* remove chroot setting so that modules are not stripping pathnames */
|
||||
free(cfg->chrootdir);
|
||||
cfg->chrootdir = NULL;
|
||||
|
||||
@@ -43,6 +43,7 @@
|
||||
#include "config.h"
|
||||
#include "libunbound/context.h"
|
||||
#include "libunbound/worker.h"
|
||||
#include "libunbound/remote.h"
|
||||
#include "util/fptr_wlist.h"
|
||||
#include "util/log.h"
|
||||
#include "services/mesh.h"
|
||||
@@ -102,7 +103,7 @@ struct outbound_entry* worker_send_query(
|
||||
socklen_t ATTR_UNUSED(addrlen), uint8_t* ATTR_UNUSED(zone),
|
||||
size_t ATTR_UNUSED(zonelen), int ATTR_UNUSED(tcp_upstream), int ATTR_UNUSED(ssl_upstream),
|
||||
char* ATTR_UNUSED(tls_auth_name), struct module_qstate* ATTR_UNUSED(q),
|
||||
int* ATTR_UNUSED(was_ratelimited))
|
||||
int* ATTR_UNUSED(was_ratelimited), int* ATTR_UNUSED(ratelimit_incremented))
|
||||
{
|
||||
log_assert(0);
|
||||
return 0;
|
||||
@@ -128,6 +129,12 @@ worker_alloc_cleanup(void* ATTR_UNUSED(arg))
|
||||
log_assert(0);
|
||||
}
|
||||
|
||||
void
|
||||
libworker_alloc_cleanup(void* ATTR_UNUSED(arg))
|
||||
{
|
||||
log_assert(0);
|
||||
}
|
||||
|
||||
struct outbound_entry* libworker_send_query(
|
||||
struct query_info* ATTR_UNUSED(qinfo), uint16_t ATTR_UNUSED(flags),
|
||||
int ATTR_UNUSED(dnssec), int ATTR_UNUSED(want_dnssec),
|
||||
@@ -136,7 +143,7 @@ struct outbound_entry* libworker_send_query(
|
||||
socklen_t ATTR_UNUSED(addrlen), uint8_t* ATTR_UNUSED(zone),
|
||||
size_t ATTR_UNUSED(zonelen), int ATTR_UNUSED(tcp_upstream), int ATTR_UNUSED(ssl_upstream),
|
||||
char* ATTR_UNUSED(tls_auth_name), struct module_qstate* ATTR_UNUSED(q),
|
||||
int* ATTR_UNUSED(was_ratelimited))
|
||||
int* ATTR_UNUSED(was_ratelimited), int* ATTR_UNUSED(ratelimit_incremented))
|
||||
{
|
||||
log_assert(0);
|
||||
return 0;
|
||||
|
||||
+12
-3
@@ -146,7 +146,9 @@ submit_query(struct http2_session* h2_session, struct sldns_buffer* buf)
|
||||
{
|
||||
int32_t stream_id;
|
||||
struct http2_stream* h2_stream;
|
||||
nghttp2_nv headers[5];
|
||||
nghttp2_nv headers[6];
|
||||
size_t num_headers = 5;
|
||||
char clen[16];
|
||||
char* qb64;
|
||||
size_t qb64_size;
|
||||
size_t qb64_expected_size;
|
||||
@@ -194,9 +196,16 @@ submit_query(struct http2_session* h2_session, struct sldns_buffer* buf)
|
||||
headers[3].value = (uint8_t*)h2_session->authority;
|
||||
headers[4].name = (uint8_t*)"content-type";
|
||||
headers[4].value = (uint8_t*)h2_session->content_type;
|
||||
if(h2_session->post) {
|
||||
snprintf(clen, sizeof(clen), "%u",
|
||||
(unsigned)sldns_buffer_remaining(buf));
|
||||
headers[5].name = (uint8_t*)"content-length";
|
||||
headers[5].value = (uint8_t*)clen;
|
||||
num_headers = 6;
|
||||
}
|
||||
|
||||
printf("Request headers\n");
|
||||
for(i=0; i<sizeof(headers)/sizeof(headers[0]); i++) {
|
||||
for(i=0; i<num_headers; i++) {
|
||||
headers[i].namelen = strlen((char*)headers[i].name);
|
||||
headers[i].valuelen = strlen((char*)headers[i].value);
|
||||
headers[i].flags = NGHTTP2_NV_FLAG_NONE;
|
||||
@@ -204,7 +213,7 @@ submit_query(struct http2_session* h2_session, struct sldns_buffer* buf)
|
||||
}
|
||||
|
||||
stream_id = nghttp2_submit_request(h2_session->session, NULL, headers,
|
||||
sizeof(headers)/sizeof(headers[0]),
|
||||
num_headers,
|
||||
(h2_session->post) ? &data_prd : NULL, h2_stream);
|
||||
if(stream_id < 0) {
|
||||
printf("Failed to submit nghttp2 request");
|
||||
|
||||
+17
-7
@@ -1137,8 +1137,11 @@ static struct ngtcp2_conn* conn_client_setup(struct doq_client_data* data)
|
||||
client_chosen_version, &cbs, &settings, ¶ms,
|
||||
NULL, /* ngtcp2_mem allocator, use default */
|
||||
data /* callback argument */);
|
||||
if(!conn) fatal_exit("could not ngtcp2_conn_client_new: %s",
|
||||
ngtcp2_strerror(rv));
|
||||
if(rv!=0) {
|
||||
conn = NULL;
|
||||
fatal_exit("could not ngtcp2_conn_client_new: %s",
|
||||
ngtcp2_strerror(rv));
|
||||
}
|
||||
data->cc_algo = settings.cc_algo;
|
||||
return conn;
|
||||
}
|
||||
@@ -1519,9 +1522,9 @@ doq_client_send_pkt(struct doq_client_data* data, uint32_t ecn, uint8_t* buf,
|
||||
}
|
||||
log_err("doq sendmsg: %s", strerror(errno));
|
||||
#ifdef HAVE_NGTCP2_CCERR_DEFAULT
|
||||
ngtcp2_ccerr_set_application_error(&data->ccerr, -1, NULL, 0);
|
||||
ngtcp2_ccerr_set_application_error(&data->ccerr, 1, NULL, 0);
|
||||
#else
|
||||
ngtcp2_connection_close_error_set_application_error(&data->last_error, -1, NULL, 0);
|
||||
ngtcp2_connection_close_error_set_application_error(&data->last_error, 1, NULL, 0);
|
||||
#endif
|
||||
return 0;
|
||||
}
|
||||
@@ -2098,7 +2101,7 @@ early_data_setup_session(struct doq_client_data* data)
|
||||
SSL_SESSION_free(session);
|
||||
return 0;
|
||||
}
|
||||
#ifdef USE_NGTCP2_CRYPTO_OSSL
|
||||
#ifdef HAVE_SSL_SET_QUIC_TLS_EARLY_DATA_ENABLED
|
||||
SSL_set_quic_tls_early_data_enabled(data->ssl, 1);
|
||||
#else
|
||||
SSL_set_quic_early_data_enabled(data->ssl, 1);
|
||||
@@ -2595,7 +2598,8 @@ struct outbound_entry* worker_send_query(
|
||||
socklen_t ATTR_UNUSED(addrlen), uint8_t* ATTR_UNUSED(zone),
|
||||
size_t ATTR_UNUSED(zonelen), int ATTR_UNUSED(tcp_upstream),
|
||||
int ATTR_UNUSED(ssl_upstream), char* ATTR_UNUSED(tls_auth_name),
|
||||
struct module_qstate* ATTR_UNUSED(q), int* ATTR_UNUSED(was_ratelimited))
|
||||
struct module_qstate* ATTR_UNUSED(q), int* ATTR_UNUSED(was_ratelimited),
|
||||
int* ATTR_UNUSED(ratelimit_incremented))
|
||||
{
|
||||
log_assert(0);
|
||||
return 0;
|
||||
@@ -2629,7 +2633,8 @@ struct outbound_entry* libworker_send_query(
|
||||
socklen_t ATTR_UNUSED(addrlen), uint8_t* ATTR_UNUSED(zone),
|
||||
size_t ATTR_UNUSED(zonelen), int ATTR_UNUSED(tcp_upstream),
|
||||
int ATTR_UNUSED(ssl_upstream), char* ATTR_UNUSED(tls_auth_name),
|
||||
struct module_qstate* ATTR_UNUSED(q), int* ATTR_UNUSED(was_ratelimited))
|
||||
struct module_qstate* ATTR_UNUSED(q), int* ATTR_UNUSED(was_ratelimited),
|
||||
int* ATTR_UNUSED(ratelimit_incremented))
|
||||
{
|
||||
log_assert(0);
|
||||
return 0;
|
||||
@@ -2671,6 +2676,11 @@ void libworker_event_done_cb(void* ATTR_UNUSED(arg), int ATTR_UNUSED(rcode),
|
||||
log_assert(0);
|
||||
}
|
||||
|
||||
void libworker_alloc_cleanup(void* ATTR_UNUSED(arg))
|
||||
{
|
||||
log_assert(0);
|
||||
}
|
||||
|
||||
int context_query_cmp(const void* ATTR_UNUSED(a), const void* ATTR_UNUSED(b))
|
||||
{
|
||||
log_assert(0);
|
||||
|
||||
+29
-4
@@ -1126,15 +1126,16 @@ outside_network_create(struct comm_base* base, size_t bufsize,
|
||||
int ATTR_UNUSED(dscp),
|
||||
struct infra_cache* infra,
|
||||
struct ub_randstate* ATTR_UNUSED(rnd),
|
||||
int ATTR_UNUSED(use_caps_for_id), int* ATTR_UNUSED(availports),
|
||||
int ATTR_UNUSED(numavailports), size_t ATTR_UNUSED(unwanted_threshold),
|
||||
int ATTR_UNUSED(use_caps_for_id),
|
||||
size_t ATTR_UNUSED(unwanted_threshold),
|
||||
int ATTR_UNUSED(outgoing_tcp_mss),
|
||||
void (*unwanted_action)(void*), void* ATTR_UNUSED(unwanted_param),
|
||||
int ATTR_UNUSED(do_udp), void* ATTR_UNUSED(sslctx),
|
||||
int ATTR_UNUSED(delayclose), int ATTR_UNUSED(tls_use_sni),
|
||||
struct dt_env* ATTR_UNUSED(dtenv), int ATTR_UNUSED(udp_connect),
|
||||
int ATTR_UNUSED(max_reuse_tcp_queries), int ATTR_UNUSED(tcp_reuse_timeout),
|
||||
int ATTR_UNUSED(tcp_auth_query_timeout))
|
||||
int ATTR_UNUSED(tcp_auth_query_timeout),
|
||||
struct shared_ports* ATTR_UNUSED(shared_ports))
|
||||
{
|
||||
struct replay_runtime* runtime = (struct replay_runtime*)base;
|
||||
struct outside_network* outnet = calloc(1,
|
||||
@@ -1275,7 +1276,8 @@ struct serviced_query* outnet_serviced_query(struct outside_network* outnet,
|
||||
socklen_t addrlen, uint8_t* zone, size_t zonelen,
|
||||
struct module_qstate* qstate, comm_point_callback_type* callback,
|
||||
void* callback_arg, sldns_buffer* ATTR_UNUSED(buff),
|
||||
struct module_env* env, int* ATTR_UNUSED(was_ratelimited))
|
||||
struct module_env* env, int* ATTR_UNUSED(was_ratelimited),
|
||||
int* ATTR_UNUSED(ratelimit_incremented))
|
||||
{
|
||||
struct replay_runtime* runtime = (struct replay_runtime*)outnet->base;
|
||||
struct fake_pending* pend = (struct fake_pending*)calloc(1,
|
||||
@@ -1980,6 +1982,20 @@ int outnet_tcp_connect(int ATTR_UNUSED(s), struct sockaddr_storage* ATTR_UNUSED(
|
||||
return 0;
|
||||
}
|
||||
|
||||
struct shared_ports* shared_ports_create(char** ATTR_UNUSED(ifs),
|
||||
int ATTR_UNUSED(num_ifs), int ATTR_UNUSED(do_ip4),
|
||||
int ATTR_UNUSED(do_ip6), int* ATTR_UNUSED(availports),
|
||||
int ATTR_UNUSED(numavailports))
|
||||
{
|
||||
return calloc(1, sizeof(struct shared_ports));
|
||||
}
|
||||
|
||||
void shared_ports_delete(struct shared_ports* shp)
|
||||
{
|
||||
if(!shp) return;
|
||||
free(shp);
|
||||
}
|
||||
|
||||
int tcp_req_info_add_meshstate(struct tcp_req_info* ATTR_UNUSED(req),
|
||||
struct mesh_area* ATTR_UNUSED(mesh), struct mesh_state* ATTR_UNUSED(m))
|
||||
{
|
||||
@@ -2021,6 +2037,15 @@ void http2_stream_remove_mesh_state(struct http2_stream* ATTR_UNUSED(h2_stream))
|
||||
{
|
||||
}
|
||||
|
||||
void doq_stream_add_meshstate(struct doq_stream* ATTR_UNUSED(stream),
|
||||
struct mesh_area* ATTR_UNUSED(mesh), struct mesh_state* ATTR_UNUSED(m))
|
||||
{
|
||||
}
|
||||
|
||||
void doq_stream_remove_mesh_state(struct doq_stream* ATTR_UNUSED(stream))
|
||||
{
|
||||
}
|
||||
|
||||
void fast_reload_service_cb(int ATTR_UNUSED(fd), short ATTR_UNUSED(event),
|
||||
void* ATTR_UNUSED(arg))
|
||||
{
|
||||
|
||||
@@ -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;
|
||||
@@ -786,3 +789,13 @@ size_t doq_table_quic_size_get(struct doq_table* ATTR_UNUSED(table))
|
||||
return 0;
|
||||
}
|
||||
#endif
|
||||
|
||||
void tcp_read_again_cb(void* ATTR_UNUSED(arg))
|
||||
{
|
||||
/* nothing */
|
||||
}
|
||||
|
||||
void tcp_more_read_again_cb(void* ATTR_UNUSED(arg))
|
||||
{
|
||||
/* nothing */
|
||||
}
|
||||
|
||||
+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) {
|
||||
|
||||
+34
-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);
|
||||
@@ -1027,6 +1027,38 @@ authzone_query_test(void)
|
||||
check_queries("example.com", zone_example_com, example_com_queries);
|
||||
}
|
||||
|
||||
/** Test chunkline_count_parens output */
|
||||
static void
|
||||
authzone_chunkline_count_parens_test(void)
|
||||
{
|
||||
sldns_buffer* buf;
|
||||
if(vbmp) printf("Testing chunkline_count_parens\n");
|
||||
buf = sldns_buffer_new(1024);
|
||||
if(!buf) fatal_exit("out of memory");
|
||||
|
||||
/* Check that escaped characters are handled, '\x', and in quotes. */
|
||||
sldns_buffer_printf(buf, "TXT \"x\" \\(");
|
||||
unit_assert(chunkline_count_parens(buf, 0) == 0);
|
||||
|
||||
sldns_buffer_clear(buf);
|
||||
sldns_buffer_printf(buf, "TXT ';x' (");
|
||||
unit_assert(chunkline_count_parens(buf, 0) == 0);
|
||||
|
||||
sldns_buffer_clear(buf);
|
||||
sldns_buffer_printf(buf, "TXT \"a;b\" (");
|
||||
unit_assert(chunkline_count_parens(buf, 0) == 1);
|
||||
|
||||
sldns_buffer_clear(buf);
|
||||
sldns_buffer_printf(buf, "TXT \\) )");
|
||||
unit_assert(chunkline_count_parens(buf, 0) == -1);
|
||||
|
||||
sldns_buffer_clear(buf);
|
||||
sldns_buffer_printf(buf, "TXT \"a\\\\\" \"(\" ");
|
||||
unit_assert(chunkline_count_parens(buf, 0) == 0);
|
||||
|
||||
sldns_buffer_free(buf);
|
||||
}
|
||||
|
||||
/** test authzone code */
|
||||
void
|
||||
authzone_test(void)
|
||||
@@ -1036,4 +1068,5 @@ authzone_test(void)
|
||||
authzone_compare_serial();
|
||||
authzone_read_test();
|
||||
authzone_query_test();
|
||||
authzone_chunkline_count_parens_test();
|
||||
}
|
||||
|
||||
@@ -141,6 +141,7 @@ static addrlen_t randomkey(addrkey_t **k, int maxlen)
|
||||
int bits = rand() % maxlen;
|
||||
int bytes = bits/8 + (bits%8>0); /*ceil*/
|
||||
*k = (addrkey_t *) malloc(bytes * sizeof(addrkey_t));
|
||||
if(!*k) fatal_exit("out of memory");
|
||||
for (byte = 0; byte < bytes; byte++) {
|
||||
(*k)[byte] = (addrkey_t)(rand() & 0xFF);
|
||||
}
|
||||
|
||||
@@ -279,10 +279,24 @@ b64_test(void)
|
||||
unit_assert(result == -1);
|
||||
}
|
||||
|
||||
/** test SVCB ech svcparam */
|
||||
static void
|
||||
svcb_ech_test(void)
|
||||
{
|
||||
uint8_t rr[LDNS_RR_BUF_SIZE];
|
||||
size_t rr_len = sizeof(rr), dname_len = 0;
|
||||
int e = sldns_str2wire_rr_buf("x. 300 IN HTTPS 1 . ech=0",
|
||||
rr, &rr_len, &dname_len, 300, NULL, 0, NULL, 0);
|
||||
unit_assert(e == LDNS_WIREPARSE_ERR_OK);
|
||||
unit_assert(rr_len == dname_len + 10 /* type,class,ttl,rdatalen */ + 7 /* rdata */);
|
||||
unit_assert(sldns_read_uint16(rr + dname_len + 8 /* rdlen */) == 7);
|
||||
}
|
||||
|
||||
void
|
||||
ldns_test(void)
|
||||
{
|
||||
unit_show_feature("sldns");
|
||||
rr_tests();
|
||||
b64_test();
|
||||
svcb_ech_test();
|
||||
}
|
||||
|
||||
@@ -1282,6 +1282,144 @@ static void localzone_test(void)
|
||||
localzone_parents_test();
|
||||
}
|
||||
|
||||
#include "services/mesh.h"
|
||||
/** mesh unit tests */
|
||||
static void mesh_test(void)
|
||||
{
|
||||
struct regional* r2, *r3;
|
||||
struct respip_client_info* c1, *c2, *c3;
|
||||
unit_show_func("services/mesh.c", "mesh_copy_client_info");
|
||||
r2 = regional_create();
|
||||
r3 = regional_create();
|
||||
if(!r2 || !r3) fatal_exit("out of memory");
|
||||
|
||||
c1 = calloc(1, sizeof(*c1));
|
||||
if(!c1) fatal_exit("out of memory");
|
||||
c1->view = calloc(1, sizeof(*c1->view));
|
||||
if(!c1->view) fatal_exit("out of memory");
|
||||
c1->view->name = strdup("view1");
|
||||
if(!c1->view->name) fatal_exit("out of memory");
|
||||
|
||||
c2 = mesh_copy_client_info(r2, c1);
|
||||
if(!c2) fatal_exit("out of memory");
|
||||
c3 = mesh_copy_client_info(r3, c2);
|
||||
if(!c3) fatal_exit("out of memory");
|
||||
|
||||
unit_assert(strcmp(c1->view->name, c2->view_name) == 0);
|
||||
unit_assert(strcmp(c1->view->name, c3->view_name) == 0);
|
||||
|
||||
/* make sure that the c3 view_name is in the r3 region. */
|
||||
unit_assert(r3->next == NULL); /* only the first chunk present atm */
|
||||
if(strlen(c3->view_name) >= r3->large_object_size) {
|
||||
char* a = r3->large_list;
|
||||
int found = 0;
|
||||
while(a) {
|
||||
if(strcmp(c3->view_name,
|
||||
a + /* ALIGNEMENT */ sizeof(uint64_t)) == 0) {
|
||||
found = 1;
|
||||
break;
|
||||
}
|
||||
a = *(char**)a;
|
||||
}
|
||||
unit_assert(found == 1);
|
||||
} else {
|
||||
/* The allocation is expected in the r3 region first chunk */
|
||||
unit_assert((uint8_t*)c3->view_name < ((uint8_t*)r3)+r3->first_size);
|
||||
}
|
||||
|
||||
regional_destroy(r2);
|
||||
/* ASAN should complain for the freed access below */
|
||||
unit_assert(strcmp(c1->view->name, c3->view_name) == 0);
|
||||
|
||||
regional_destroy(r3);
|
||||
free(c1->view->name);
|
||||
free(c1->view);
|
||||
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);
|
||||
@@ -1354,8 +1492,10 @@ main(int argc, char* argv[])
|
||||
zonemd_test();
|
||||
tcpreuse_test();
|
||||
msgparse_test();
|
||||
packed_rrset_test();
|
||||
edns_ede_answer_encode_test();
|
||||
localzone_test();
|
||||
mesh_test();
|
||||
#ifdef CLIENT_SUBNET
|
||||
ecs_test();
|
||||
#endif /* CLIENT_SUBNET */
|
||||
@@ -1389,6 +1529,9 @@ main(int argc, char* argv[])
|
||||
# ifdef HAVE_RAND_CLEANUP
|
||||
RAND_cleanup();
|
||||
# endif
|
||||
#ifdef HAVE_OPENSSL_CLEANUP
|
||||
OPENSSL_cleanup();
|
||||
#endif
|
||||
#elif defined(HAVE_NSS)
|
||||
if(NSS_Shutdown() != SECSuccess)
|
||||
fatal_exit("could not shutdown NSS");
|
||||
|
||||
@@ -41,6 +41,7 @@
|
||||
#include "config.h"
|
||||
#include "testcode/unitmain.h"
|
||||
#include "util/log.h"
|
||||
#include "util/net_help.h"
|
||||
#include "util/random.h"
|
||||
#include "services/outside_network.h"
|
||||
|
||||
@@ -479,6 +480,278 @@ static void reuse_write_wait_test(void)
|
||||
check_reuse_write_wait_removal(1, &reuse, store, 0, 1);
|
||||
}
|
||||
|
||||
static void shared_port_test_ifs(void)
|
||||
{
|
||||
struct shared_ports* shp;
|
||||
struct shared_ports_if* shpif;
|
||||
char* ifs[] = {"1.2.3.4", "1.2.3.5", "::1:2", "::1:3"};
|
||||
int availports[] = {1, 2, 3, 4};
|
||||
struct sockaddr_storage addr;
|
||||
socklen_t addrlen;
|
||||
|
||||
shp = shared_ports_create(ifs, 4, 1, 1, availports, 4);
|
||||
unit_assert(shp);
|
||||
|
||||
if(!ipstrtoaddr("1.2.3.4", UNBOUND_DNS_PORT, &addr, &addrlen))
|
||||
log_err("could not parse");
|
||||
shpif = shared_ports_find_if(shp, &addr, addrlen, 0);
|
||||
unit_assert(shpif);
|
||||
|
||||
if(!ipstrtoaddr("1.2.3.5", UNBOUND_DNS_PORT, &addr, &addrlen))
|
||||
log_err("could not parse");
|
||||
shpif = shared_ports_find_if(shp, &addr, addrlen, 0);
|
||||
unit_assert(shpif);
|
||||
|
||||
if(!ipstrtoaddr("::1:2", UNBOUND_DNS_PORT, &addr, &addrlen))
|
||||
log_err("could not parse");
|
||||
shpif = shared_ports_find_if(shp, &addr, addrlen, 0);
|
||||
unit_assert(shpif);
|
||||
|
||||
if(!ipstrtoaddr("::1:3", UNBOUND_DNS_PORT, &addr, &addrlen))
|
||||
log_err("could not parse");
|
||||
shpif = shared_ports_find_if(shp, &addr, addrlen, 0);
|
||||
unit_assert(shpif);
|
||||
|
||||
shared_ports_delete(shp);
|
||||
}
|
||||
|
||||
/** See if a port is on the shared_ports ports list */
|
||||
static int
|
||||
pif_list_contains(struct shared_ports_if* shpif, int item)
|
||||
{
|
||||
int i;
|
||||
unit_assert(shpif->inuse >= 0 && shpif->inuse <= shpif->avail_total);
|
||||
for(i=0; i< shpif->avail_total - shpif->inuse; i++) {
|
||||
if(shpif->avail_ports[i] == item)
|
||||
return 1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
/** See if a number of ports are on the shared_ports list */
|
||||
static int
|
||||
pif_list_contains_items(struct shared_ports_if* shpif, int item1,
|
||||
int item2, int item3, int item4)
|
||||
{
|
||||
if(item1 != -1 && !pif_list_contains(shpif, item1))
|
||||
return 0;
|
||||
if(item2 != -1 && !pif_list_contains(shpif, item2))
|
||||
return 0;
|
||||
if(item3 != -1 && !pif_list_contains(shpif, item3))
|
||||
return 0;
|
||||
if(item4 != -1 && !pif_list_contains(shpif, item4))
|
||||
return 0;
|
||||
return 1;
|
||||
}
|
||||
|
||||
static void shared_port_test_port(void)
|
||||
{
|
||||
struct shared_ports* shp;
|
||||
struct shared_ports_if* shpif;
|
||||
char* ifs[] = {"1.2.3.4", "1.2.3.5"};
|
||||
int availports[] = {1, 2, 3, 4};
|
||||
struct sockaddr_storage addr;
|
||||
socklen_t addrlen;
|
||||
int p1, p2, p3, reused;
|
||||
struct ub_randstate* rnd;
|
||||
|
||||
rnd = ub_initstate(NULL);
|
||||
unit_assert(rnd);
|
||||
|
||||
shp = shared_ports_create(ifs, 2, 1, 1, availports, 4);
|
||||
unit_assert(shp);
|
||||
|
||||
if(!ipstrtoaddr("1.2.3.4", UNBOUND_DNS_PORT, &addr, &addrlen))
|
||||
log_err("could not parse");
|
||||
shpif = shared_ports_find_if(shp, &addr, addrlen, 0);
|
||||
unit_assert(shpif);
|
||||
|
||||
unit_assert(shpif->avail_total == 4);
|
||||
unit_assert(shpif->inuse == 0);
|
||||
unit_assert(pif_list_contains_items(shpif, 1, 2, 3, 4));
|
||||
|
||||
if(!shared_ports_fetch_random(shp, shpif, rnd,
|
||||
0, 0, &p1, &reused)) {
|
||||
unit_assert(0); /* should succeed */
|
||||
}
|
||||
unit_assert(reused == 0);
|
||||
unit_assert(p1 != 0);
|
||||
unit_assert(!pif_list_contains(shpif, p1));
|
||||
if(p1 != 1) unit_assert(pif_list_contains(shpif, 1));
|
||||
if(p1 != 2) unit_assert(pif_list_contains(shpif, 2));
|
||||
if(p1 != 3) unit_assert(pif_list_contains(shpif, 3));
|
||||
if(p1 != 4) unit_assert(pif_list_contains(shpif, 4));
|
||||
unit_assert(shpif->avail_total == 4);
|
||||
unit_assert(shpif->inuse == 1);
|
||||
|
||||
shared_ports_return_port(shp, shpif, p1);
|
||||
unit_assert(shpif->avail_total == 4);
|
||||
unit_assert(shpif->inuse == 0);
|
||||
unit_assert(pif_list_contains_items(shpif, 1, 2, 3, 4));
|
||||
|
||||
/* pick up two items */
|
||||
if(!shared_ports_fetch_random(shp, shpif, rnd,
|
||||
0, 0, &p1, &reused)) {
|
||||
unit_assert(0); /* should succeed */
|
||||
}
|
||||
unit_assert(reused == 0);
|
||||
unit_assert(p1 != 0);
|
||||
if(!shared_ports_fetch_random(shp, shpif, rnd,
|
||||
0, 0, &p2, &reused)) {
|
||||
unit_assert(0); /* should succeed */
|
||||
}
|
||||
unit_assert(reused == 0);
|
||||
unit_assert(p2 != 0);
|
||||
unit_assert(!pif_list_contains(shpif, p1));
|
||||
unit_assert(!pif_list_contains(shpif, p2));
|
||||
if(p1 != 1 && p2 != 1) unit_assert(pif_list_contains(shpif, 1));
|
||||
if(p1 != 2 && p2 != 2) unit_assert(pif_list_contains(shpif, 2));
|
||||
if(p1 != 3 && p2 != 3) unit_assert(pif_list_contains(shpif, 3));
|
||||
if(p1 != 4 && p2 != 4) unit_assert(pif_list_contains(shpif, 4));
|
||||
unit_assert(shpif->avail_total == 4);
|
||||
unit_assert(shpif->inuse == 2);
|
||||
|
||||
shared_ports_return_port(shp, shpif, p1);
|
||||
unit_assert(pif_list_contains(shpif, p1));
|
||||
unit_assert(shpif->avail_total == 4);
|
||||
unit_assert(shpif->inuse == 1);
|
||||
|
||||
shared_ports_return_port(shp, shpif, p2);
|
||||
unit_assert(pif_list_contains(shpif, p2));
|
||||
unit_assert(shpif->avail_total == 4);
|
||||
unit_assert(shpif->inuse == 0);
|
||||
unit_assert(pif_list_contains_items(shpif, 1, 2, 3, 4));
|
||||
|
||||
/* pick up three items */
|
||||
if(!shared_ports_fetch_random(shp, shpif, rnd,
|
||||
0, 0, &p1, &reused)) {
|
||||
unit_assert(0); /* should succeed */
|
||||
}
|
||||
unit_assert(reused == 0);
|
||||
unit_assert(p1 != 0);
|
||||
if(!shared_ports_fetch_random(shp, shpif, rnd,
|
||||
0, 0, &p2, &reused)) {
|
||||
unit_assert(0); /* should succeed */
|
||||
}
|
||||
unit_assert(reused == 0);
|
||||
unit_assert(p2 != 0);
|
||||
if(!shared_ports_fetch_random(shp, shpif, rnd,
|
||||
0, 0, &p3, &reused)) {
|
||||
unit_assert(0); /* should succeed */
|
||||
}
|
||||
unit_assert(reused == 0);
|
||||
unit_assert(p3 != 0);
|
||||
unit_assert(!pif_list_contains(shpif, p1));
|
||||
unit_assert(!pif_list_contains(shpif, p2));
|
||||
unit_assert(!pif_list_contains(shpif, p3));
|
||||
if(p1 != 1 && p2 != 1 && p3 != 1)
|
||||
unit_assert(pif_list_contains(shpif, 1));
|
||||
if(p1 != 2 && p2 != 2 && p3 != 2)
|
||||
unit_assert(pif_list_contains(shpif, 2));
|
||||
if(p1 != 3 && p2 != 3 && p3 != 3)
|
||||
unit_assert(pif_list_contains(shpif, 3));
|
||||
if(p1 != 4 && p2 != 4 && p3 != 4)
|
||||
unit_assert(pif_list_contains(shpif, 4));
|
||||
unit_assert(shpif->avail_total == 4);
|
||||
unit_assert(shpif->inuse == 3);
|
||||
|
||||
shared_ports_return_port(shp, shpif, p1);
|
||||
unit_assert(pif_list_contains(shpif, p1));
|
||||
unit_assert(shpif->avail_total == 4);
|
||||
unit_assert(shpif->inuse == 2);
|
||||
|
||||
shared_ports_return_port(shp, shpif, p2);
|
||||
unit_assert(pif_list_contains(shpif, p2));
|
||||
unit_assert(shpif->avail_total == 4);
|
||||
unit_assert(shpif->inuse == 1);
|
||||
|
||||
shared_ports_return_port(shp, shpif, p3);
|
||||
unit_assert(pif_list_contains(shpif, p3));
|
||||
unit_assert(shpif->avail_total == 4);
|
||||
unit_assert(shpif->inuse == 0);
|
||||
unit_assert(pif_list_contains_items(shpif, 1, 2, 3, 4));
|
||||
|
||||
/* pick up all four items */
|
||||
if(!shared_ports_fetch_random(shp, shpif, rnd,
|
||||
0, 0, &p1, &reused)) {
|
||||
unit_assert(0); /* should succeed */
|
||||
}
|
||||
unit_assert(reused == 0);
|
||||
unit_assert(p1 != 0);
|
||||
|
||||
if(!shared_ports_fetch_random(shp, shpif, rnd,
|
||||
0, 0, &p1, &reused)) {
|
||||
unit_assert(0); /* should succeed */
|
||||
}
|
||||
unit_assert(reused == 0);
|
||||
unit_assert(p1 != 0);
|
||||
|
||||
if(!shared_ports_fetch_random(shp, shpif, rnd,
|
||||
0, 0, &p1, &reused)) {
|
||||
unit_assert(0); /* should succeed */
|
||||
}
|
||||
unit_assert(reused == 0);
|
||||
unit_assert(p1 != 0);
|
||||
|
||||
if(!shared_ports_fetch_random(shp, shpif, rnd,
|
||||
0, 0, &p1, &reused)) {
|
||||
unit_assert(0); /* should succeed */
|
||||
}
|
||||
unit_assert(reused == 0);
|
||||
unit_assert(p1 != 0);
|
||||
unit_assert(!pif_list_contains(shpif, 1));
|
||||
unit_assert(!pif_list_contains(shpif, 2));
|
||||
unit_assert(!pif_list_contains(shpif, 3));
|
||||
unit_assert(!pif_list_contains(shpif, 4));
|
||||
unit_assert(shpif->avail_total == 4);
|
||||
unit_assert(shpif->inuse == 4);
|
||||
|
||||
/* more fetches fail, it is fully inuse. */
|
||||
unit_assert(!shared_ports_fetch_random(shp, shpif, rnd, 0, 0, &p2,
|
||||
&reused));
|
||||
unit_assert(!shared_ports_fetch_random(shp, shpif, rnd, 0, 0, &p3,
|
||||
&reused));
|
||||
unit_assert(shpif->avail_total == 4);
|
||||
unit_assert(shpif->inuse == 4);
|
||||
|
||||
/* reuse is then always the case */
|
||||
if(!shared_ports_fetch_random(shp, shpif, rnd,
|
||||
0 /* can reuse */, 4 /* reusenum */, &p1, &reused)) {
|
||||
unit_assert(0); /* should succeed */
|
||||
}
|
||||
unit_assert(reused == 1);
|
||||
unit_assert(p1 >= 0 && p1 < 4 /* reusenum */);
|
||||
|
||||
if(!shared_ports_fetch_random(shp, shpif, rnd,
|
||||
0 /* can reuse */, 4 /* reusenum */, &p1, &reused)) {
|
||||
unit_assert(0); /* should succeed */
|
||||
}
|
||||
unit_assert(reused == 1);
|
||||
unit_assert(p1 >= 0 && p1 < 4 /* reusenum */);
|
||||
|
||||
/* return all the ports */
|
||||
shared_ports_return_port(shp, shpif, 1);
|
||||
unit_assert(pif_list_contains(shpif, 1));
|
||||
unit_assert(shpif->avail_total == 4);
|
||||
unit_assert(shpif->inuse == 3);
|
||||
shared_ports_return_port(shp, shpif, 2);
|
||||
unit_assert(pif_list_contains(shpif, 2));
|
||||
unit_assert(shpif->avail_total == 4);
|
||||
unit_assert(shpif->inuse == 2);
|
||||
shared_ports_return_port(shp, shpif, 3);
|
||||
unit_assert(pif_list_contains(shpif, 3));
|
||||
unit_assert(shpif->avail_total == 4);
|
||||
unit_assert(shpif->inuse == 1);
|
||||
shared_ports_return_port(shp, shpif, 4);
|
||||
unit_assert(pif_list_contains(shpif, 4));
|
||||
unit_assert(shpif->avail_total == 4);
|
||||
unit_assert(shpif->inuse == 0);
|
||||
unit_assert(pif_list_contains_items(shpif, 1, 2, 3, 4));
|
||||
|
||||
shared_ports_delete(shp);
|
||||
ub_randfree(rnd);
|
||||
}
|
||||
|
||||
void tcpreuse_test(void)
|
||||
{
|
||||
unit_show_feature("tcp_reuse");
|
||||
@@ -486,4 +759,7 @@ void tcpreuse_test(void)
|
||||
tcp_reuse_tree_list_test();
|
||||
waiting_tcp_list_test();
|
||||
reuse_write_wait_test();
|
||||
unit_show_feature("shared_ports");
|
||||
shared_port_test_ifs();
|
||||
shared_port_test_port();
|
||||
}
|
||||
|
||||
+143
-1
@@ -196,7 +196,7 @@ verifytest_rrset(struct module_env* env, struct val_env* ve,
|
||||
setup_sigalg(dnskey, sigalg); /* check all algorithms in the dnskey */
|
||||
/* ok to give null as qstate here, won't be used for answer section. */
|
||||
sec = dnskeyset_verify_rrset(env, ve, rrset, dnskey, sigalg, &reason,
|
||||
NULL, LDNS_SECTION_ANSWER, NULL, &verified, reasonbuf,
|
||||
NULL, LDNS_SECTION_ANSWER, NULL, NULL, &verified, reasonbuf,
|
||||
sizeof(reasonbuf));
|
||||
if(vsig) {
|
||||
printf("verify outcome is: %s %s\n", sec_status_to_string(sec),
|
||||
@@ -510,6 +510,146 @@ nsec3_hash_test(const char* fname)
|
||||
sldns_buffer_free(buf);
|
||||
}
|
||||
|
||||
/** Test the rrset_canonicalize_to_buffer function to see if the
|
||||
* size of canon_owner name is properly checked for. */
|
||||
static void
|
||||
canon_owner_buf_test(void)
|
||||
{
|
||||
struct regional* region;
|
||||
sldns_buffer* buf;
|
||||
struct ub_packed_rrset_key k;
|
||||
struct packed_rrset_data d;
|
||||
size_t rr_len[2];
|
||||
time_t rr_ttl[2];
|
||||
uint8_t* rr_data[2];
|
||||
int ret;
|
||||
unit_show_func("validator/val_sigcrypt.c",
|
||||
"rrset_canonicalize_to_buffer");
|
||||
region = regional_create();
|
||||
if(!region)
|
||||
fatal_exit("out of memory");
|
||||
/* Purposefully a very small buffer, to overflow it */
|
||||
buf = sldns_buffer_new(28);
|
||||
if(!buf)
|
||||
fatal_exit("out of memory");
|
||||
|
||||
/* An RRset to canonicalize. The buffer is made smaller, so
|
||||
* it can fail on bounds checks. */
|
||||
memset(&d, 0, sizeof(d));
|
||||
d.ttl = 3600;
|
||||
d.count = 1;
|
||||
d.rrsig_count = 1;
|
||||
d.rr_len = rr_len;
|
||||
d.rr_ttl = rr_ttl;
|
||||
d.rr_data = rr_data;
|
||||
rr_len[0] = 18;
|
||||
rr_len[1] = 36;
|
||||
rr_ttl[0] = 3600;
|
||||
rr_ttl[1] = 3600;
|
||||
rr_data[0] = (uint8_t*)"\x00\x10\x0Fzzaaaaaaaaaaaaa";
|
||||
rr_data[1] = (uint8_t*)"\x00\x24\x00\x06\x08\x3\x01\x02\x03\x04\x01\x02\x03\x04\x01\x02\x03\x04\x12\x34\x03zzz\x00zzaaaaaaaaaaa";
|
||||
|
||||
memset(&k, 0, sizeof(k));
|
||||
k.rk.dname = (uint8_t*) "\x0f" "aaaaaaaaaaaaaaa" "\x00";
|
||||
k.rk.dname_len = 17;
|
||||
k.rk.type = htons(LDNS_RR_TYPE_TXT);
|
||||
k.rk.rrset_class = htons(LDNS_RR_CLASS_IN);
|
||||
k.entry.data = &d;
|
||||
|
||||
/* There should be no buffer overflow, assertion failure, here */
|
||||
ret = rrset_canonicalize_to_buffer(region, buf, &k);
|
||||
unit_assert(ret == 0);
|
||||
|
||||
regional_destroy(region);
|
||||
sldns_buffer_free(buf);
|
||||
}
|
||||
|
||||
/** Test if ds_digest_match_dnskey that calls ds_create_dnskey_digest,
|
||||
* checks the buffer size. */
|
||||
static void
|
||||
dnskey_ds_digest_test(void)
|
||||
{
|
||||
struct regional* region;
|
||||
sldns_buffer* buf;
|
||||
struct module_env env;
|
||||
struct ub_packed_rrset_key k1, k2;
|
||||
struct packed_rrset_data d1, d2;
|
||||
size_t rr_len1[1], rr_len2[1];
|
||||
time_t rr_ttl1[1], rr_ttl2[1];
|
||||
uint8_t* rr_rdata1[1], *rr_rdata2[1];
|
||||
int ret;
|
||||
unit_show_func("validator/val_sigcrypt.c", "ds_digest_match_dnskey");
|
||||
region = regional_create();
|
||||
if(!region)
|
||||
fatal_exit("out of memory");
|
||||
/* Purposefully a very small buffer, to overflow it */
|
||||
buf = sldns_buffer_new(28);
|
||||
if(!buf)
|
||||
fatal_exit("out of memory");
|
||||
memset(&env, 0, sizeof(env));
|
||||
env.scratch = region;
|
||||
env.scratch_buffer = buf;
|
||||
|
||||
/* A DNSKEY and DS RRset to match together. The buffer is made
|
||||
* smaller, so it can fail on bounds checks. */
|
||||
memset(&d1, 0, sizeof(d1));
|
||||
d1.ttl = 3600;
|
||||
d1.count = 1;
|
||||
d1.rr_len = rr_len1;
|
||||
d1.rr_ttl = rr_ttl1;
|
||||
d1.rr_data = rr_rdata1;
|
||||
rr_len1[0] = 38;
|
||||
rr_ttl1[0] = 3600;
|
||||
/* DS rdata has: keytag (2bytes), algorithm (1byte),
|
||||
* digesttype (1byte), digest (remainder). */
|
||||
rr_rdata1[0] = (uint8_t*)"\x00\x24"
|
||||
"\x12\x34"
|
||||
"\x08" /* RSASHA256 */
|
||||
"\x02" /* SHA256 */
|
||||
"0123456789abcdef0123456789abcdef"; /* 32 bytes */
|
||||
;
|
||||
|
||||
memset(&k1, 0, sizeof(k1));
|
||||
k1.rk.dname = (uint8_t*) "\x03" "foo" "\x00";
|
||||
k1.rk.dname_len = 5;
|
||||
k1.rk.type = htons(LDNS_RR_TYPE_DS);
|
||||
k1.rk.rrset_class = htons(LDNS_RR_CLASS_IN);
|
||||
k1.entry.data = &d1;
|
||||
|
||||
memset(&d2, 0, sizeof(d2));
|
||||
d2.ttl = 3600;
|
||||
d2.count = 1;
|
||||
d2.rr_len = rr_len2;
|
||||
d2.rr_ttl = rr_ttl2;
|
||||
d2.rr_data = rr_rdata2;
|
||||
rr_len2[0] = 38;
|
||||
rr_ttl2[0] = 3600;
|
||||
/* DNSKEY rdata has: flags (2bytes), protocol (1byte),
|
||||
* algorithm (1byte), publickey (remainder). */
|
||||
rr_rdata2[0] = (uint8_t*)"\x00\x24"
|
||||
"\x01\x01" /* KSK */
|
||||
"\x03" /* DNSSEC_KEYPROTO */
|
||||
"\x08" /* RSASHA256 */
|
||||
"0123456789abcdef0123456789abcdef"; /* 32 bytes of content */
|
||||
;
|
||||
|
||||
memset(&k2, 0, sizeof(k2));
|
||||
k2.rk.dname = (uint8_t*) "\x03" "foo" "\x00";
|
||||
k2.rk.dname_len = 5;
|
||||
k2.rk.type = htons(LDNS_RR_TYPE_DNSKEY);
|
||||
k2.rk.rrset_class = htons(LDNS_RR_CLASS_IN);
|
||||
k2.entry.data = &d2;
|
||||
/* 36 byte rdata length for DNSKEY (38-2), and dname length of 5,
|
||||
* exceeds the (small) buffer size. */
|
||||
|
||||
/* There should be no buffer overflow, assertion failure, here */
|
||||
ret = ds_digest_match_dnskey(&env, &k2, 0, &k1, 0);
|
||||
unit_assert(ret == 0);
|
||||
|
||||
regional_destroy(region);
|
||||
sldns_buffer_free(buf);
|
||||
}
|
||||
|
||||
#define xstr(s) str(s)
|
||||
#define str(s) #s
|
||||
|
||||
@@ -724,4 +864,6 @@ verify_test(void)
|
||||
#endif
|
||||
nsectest();
|
||||
nsec3_hash_test(SRCDIRSTR "/testdata/test_nsec3_hash.1");
|
||||
dnskey_ds_digest_test();
|
||||
canon_owner_buf_test();
|
||||
}
|
||||
|
||||
@@ -85,6 +85,15 @@ for input in $PRE/testdata/*.rpl $PRE/testdata/*.crpl; do
|
||||
fi
|
||||
fi
|
||||
|
||||
# detect if ECDSA is needed
|
||||
if echo $cleaninput | grep ecdsa >/dev/null 2>&1; then
|
||||
if $PRE/testbound -e >/dev/null 2>&1; then
|
||||
: # ECDSA is supported
|
||||
else
|
||||
continue
|
||||
fi
|
||||
fi
|
||||
|
||||
# detect if CLIENT_SUBNET is needed
|
||||
if echo $cleaninput | grep subnet >/dev/null 2>&1; then
|
||||
if $PRE/testbound -c >/dev/null 2>&1; then
|
||||
|
||||
@@ -2,6 +2,7 @@
|
||||
server:
|
||||
do-not-query-localhost: no
|
||||
fake-sha1: yes
|
||||
verbosity: 8
|
||||
forward-zone:
|
||||
name: "."
|
||||
forward-addr: "127.0.0.1@@TOPORT@"
|
||||
|
||||
+3
-1
@@ -35,11 +35,13 @@ function check_insecure() {
|
||||
# test with good start key, and must do 5011 (no URL possible)
|
||||
echo "*** TEST 1 ***"
|
||||
echo $DS > root.key
|
||||
$PRE/unbound-anchor -x "notexist.xml" -s "notexist.p7s" $OPTS
|
||||
cat root.key
|
||||
$PRE/unbound-anchor -x "notexist.xml" -s "notexist.p7s" $OPTS -vvvv
|
||||
if test $? != 0; then
|
||||
echo "Exitcode not OK"
|
||||
exit 1
|
||||
fi
|
||||
cat root.key
|
||||
check_works
|
||||
# save for test 5
|
||||
cp root.key root.key.probed
|
||||
|
||||
Binary file not shown.
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user