mirror of
https://github.com/NLnetLabs/unbound.git
synced 2026-08-17 21:25:50 +02:00
Compare commits
350
Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
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 | ||
|
|
75b6dba593 | ||
|
|
138fb48eac | ||
|
|
dae7a37974 | ||
|
|
8ae4b4545d | ||
|
|
c343fff3a4 | ||
|
|
a794c87578 | ||
|
|
ef5ca84360 | ||
|
|
8d8fa42266 | ||
|
|
a587535c5d | ||
|
|
94d5babaee | ||
|
|
fe946ba4e9 | ||
|
|
6a31e470f8 | ||
|
|
e577695aeb | ||
|
|
a58bd6cb1e | ||
|
|
4bad944ae4 | ||
|
|
594182f109 | ||
|
|
53c261cb33 | ||
|
|
8703d9a5be | ||
|
|
aa9f1e68ff | ||
|
|
84a4f556b1 | ||
|
|
5b166dbf0a | ||
|
|
9e2233b821 | ||
|
|
13716dc8be | ||
|
|
8ada1bd88d | ||
|
|
9c80bb9fb0 | ||
|
|
33e2863862 | ||
|
|
027e23a11d | ||
|
|
62e8db1c6a | ||
|
|
581b2f31bc | ||
|
|
25fe602024 | ||
|
|
df0e86de49 | ||
|
|
e49b550cf3 | ||
|
|
07c96792f2 | ||
|
|
84ab430e11 | ||
|
|
53499e4a88 | ||
|
|
8a25a97687 | ||
|
|
c112bcf2fd | ||
|
|
9de549c498 | ||
|
|
84c645e7b3 | ||
|
|
197a425c7d | ||
|
|
311054728d | ||
|
|
6d74856212 | ||
|
|
d489e6027e | ||
|
|
e1d146d6b0 | ||
|
|
eb2fe8df8d | ||
|
|
86a8be75f0 | ||
|
|
52fc5ee374 | ||
|
|
82359c8fb1 | ||
|
|
c996671a1f | ||
|
|
e233a1ef65 | ||
|
|
06ff9f20d0 | ||
|
|
af209a12ea | ||
|
|
84ac7e1b58 | ||
|
|
24d502763c | ||
|
|
99c61c19ac | ||
|
|
cb05e9d525 | ||
|
|
abddd4e270 | ||
|
|
656b412492 | ||
|
|
f15a46fcd4 | ||
|
|
8d434bf744 | ||
|
|
13b269d398 | ||
|
|
7aff88881a | ||
|
|
b97bd3a1fc | ||
|
|
6aa5ad85f4 | ||
|
|
42b19c20c1 | ||
|
|
db1fe8b475 | ||
|
|
f4f964f4fb | ||
|
|
a2272860de | ||
|
|
95083d4377 | ||
|
|
5ce0bf5281 | ||
|
|
6a0d5e2cb1 | ||
|
|
330d5211c9 | ||
|
|
2dc28a249a | ||
|
|
c5f14dc880 | ||
|
|
a2ace114de | ||
|
|
2e9b880718 | ||
|
|
a0ec6cd946 | ||
|
|
ea36979c40 | ||
|
|
315077b9e6 | ||
|
|
535d899bef | ||
|
|
8656cfd4c8 | ||
|
|
8f44ddb7de | ||
|
|
4484dc3954 | ||
|
|
eb3bba0724 | ||
|
|
2eff1d8ab5 | ||
|
|
4672fa5b53 | ||
|
|
18029fc44f | ||
|
|
5c6f56f8f1 | ||
|
|
9af29c3ed1 | ||
|
|
76ef8c5803 | ||
|
|
94ef1a8fee | ||
|
|
683241a2f5 | ||
|
|
92ab54641e | ||
|
|
da3812953a | ||
|
|
1bd7c8dfee | ||
|
|
8f96ae7acf | ||
|
|
c4f8e60c85 | ||
|
|
a296b248b0 | ||
|
|
1ef131299a | ||
|
|
5b58a872ef | ||
|
|
94b04d6d46 | ||
|
|
f1a65eb4e8 | ||
|
|
38e1e3eec3 | ||
|
|
bff3d762ff | ||
|
|
fb322f3e87 | ||
|
|
2feee13735 | ||
|
|
1d36696462 | ||
|
|
aa4e2a9e69 | ||
|
|
8e04d04949 | ||
|
|
c5627dbd52 | ||
|
|
014ed9c5ff | ||
|
|
16e1e6d375 | ||
|
|
1a9a4e4ca1 | ||
|
|
f7f638e18f | ||
|
|
c956aea93d | ||
|
|
4556a4f490 | ||
|
|
1cdddf0fe9 | ||
|
|
18fec256b7 | ||
|
|
567c70dada | ||
|
|
8b4b2a88f7 | ||
|
|
faf40c97fc |
@@ -173,40 +173,10 @@ jobs:
|
||||
cross_platform_config: "--enable-debug --disable-flto --with-libevent --disable-static"
|
||||
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
- uses: actions/checkout@v7
|
||||
with:
|
||||
submodules: recursive
|
||||
submodules: false
|
||||
persist-credentials: false
|
||||
- name: test_windows_configure
|
||||
if: ${{ matrix.test_windows == 'yes' }}
|
||||
shell: bash
|
||||
run: |
|
||||
# The run starts with mount points for /c, /d, and
|
||||
# C:/Program Files/Git on /
|
||||
# C:/Program Files/Git/usr/bin on /bin
|
||||
# C:/Users/RUNNER~1/AppData/Local/Temp on /tmp
|
||||
echo "mount"
|
||||
mount || echo "ignored"
|
||||
echo "mount -o bind /c/msys64/usr /usr"
|
||||
mount -o bind /c/msys64/usr /usr || echo "ignored"
|
||||
# Now there is:
|
||||
# C:/msys64 on /
|
||||
# C:/msys64/usr/bin on /bin
|
||||
# And those mount points should go away for the next 'run:' shell.
|
||||
echo "mount"
|
||||
mount || echo "ignored"
|
||||
# probably installs to C:\msys64\usr\bin\bash.exe
|
||||
echo "pacman -S --noconfirm autotools"
|
||||
C:/msys64/usr/bin/pacman -S --noconfirm autotools
|
||||
echo "rm -f aclocal.m4"
|
||||
rm -f aclocal.m4
|
||||
# The paths are mounted, so that /c/msys64/usr/share/autoconf-..,
|
||||
# /c/msys64/usr/share/aclocal-.., /c/msys64/usr/share/automake-..
|
||||
# are in /usr. Also for /usr/bin, autoreconf is from
|
||||
# /c/msys64/usr/bin.
|
||||
echo "autoreconf -fi"
|
||||
#PATH="/c/msys64/usr/bin:$PATH" autoreconf -fi || echo "ignored"
|
||||
autoreconf -fi
|
||||
- name: test_windows
|
||||
if: ${{ matrix.test_windows == 'yes' }}
|
||||
env:
|
||||
@@ -219,9 +189,8 @@ jobs:
|
||||
cd ..
|
||||
export prepath=`pwd`
|
||||
echo prepath=${prepath}
|
||||
# The mount should have the git directories.
|
||||
echo "mount"
|
||||
mount || echo "ignored"
|
||||
# parralel build option
|
||||
export MINJ="-j4"
|
||||
echo "choco install winflexbison3"
|
||||
choco install winflexbison3
|
||||
echo 'LEX="win_flex"'
|
||||
@@ -239,13 +208,13 @@ jobs:
|
||||
#sed -e 's/use Pod::Usage//' < Configure > Configure.fix
|
||||
# ./Configure.fix no-shared no-asm -DOPENSSL_NO_CAPIENG mingw64 --prefix="$prepath/openssl"
|
||||
# pacman is used to install for msys2, with
|
||||
# C:/msys64/usr/bin/pacman -S --noconfirm perl
|
||||
# C:/msys64/usr/bin/pacman -S perl
|
||||
echo "C:/msys64/usr/bin/perl ./Configure no-shared no-asm -DOPENSSL_NO_CAPIENG mingw64 --prefix=\""$prepath/openssl"\" PERL=\"C:/msys64/usr/bin/perl\""
|
||||
C:/msys64/usr/bin/perl ./Configure no-shared no-asm -DOPENSSL_NO_CAPIENG mingw64 --prefix="$prepath/openssl" PERL="C:/msys64/usr/bin/perl"
|
||||
# make the libs only, build faster
|
||||
echo "make build_libs"
|
||||
#make
|
||||
make build_libs
|
||||
#make $MINJ
|
||||
make $MINJ build_libs
|
||||
mv Makefile Makefile.orig
|
||||
# fixup \\ in the installtop to /.
|
||||
echo "fixup INSTALLTOP"
|
||||
@@ -277,7 +246,7 @@ jobs:
|
||||
mv xmlwf/Makefile xmlwf/Makefile.orig
|
||||
sed -e 's/SHELL/SHELLZZ/g' < xmlwf/Makefile.orig > xmlwf/Makefile
|
||||
echo "make"
|
||||
make
|
||||
make $MINJ
|
||||
echo "make install"
|
||||
make install
|
||||
cd ..
|
||||
@@ -285,7 +254,7 @@ jobs:
|
||||
cd unbound
|
||||
echo "./configure --enable-debug --enable-static-exe --disable-flto \"--with-ssl=$prepath/openssl\" --with-libexpat=\"$prepath/expat\" --disable-shared"
|
||||
./configure --enable-debug --enable-static-exe --disable-flto "--with-ssl=$prepath/openssl" --with-libexpat="$prepath/expat" --disable-shared
|
||||
make
|
||||
make $MINJ
|
||||
# specific test output
|
||||
#make testbound.exe; ./testbound.exe -s
|
||||
#make testbound; ./testbound.exe -p testdata/acl.rpl -o -vvvv
|
||||
@@ -328,8 +297,6 @@ jobs:
|
||||
./contrib/android/install_expat.sh
|
||||
echo "::endgroup::"
|
||||
echo "::group::configure"
|
||||
echo "autoreconf -fi"
|
||||
autoreconf -fi
|
||||
echo "./configure ${CONFIG_OPTS}"
|
||||
./configure ${CONFIG_OPTS}
|
||||
echo "::endgroup::"
|
||||
@@ -349,7 +316,6 @@ jobs:
|
||||
IOS_CPU: ${{ matrix.IOS_CPU }}
|
||||
run: |
|
||||
#(already installed) ./contrib/ios/install_tools.sh
|
||||
brew install autoconf automake libtool make
|
||||
export AUTOTOOLS_BUILD="$(./config.guess)"
|
||||
echo AUTOTOOLS_BUILD=${AUTOTOOLS_BUILD}
|
||||
export IOS_PREFIX="$HOME/$IOS_SDK-$IOS_CPU"
|
||||
@@ -371,8 +337,6 @@ jobs:
|
||||
./contrib/ios/install_expat.sh
|
||||
echo "::endgroup::"
|
||||
echo "::group::configure"
|
||||
echo "autoreconf -fi"
|
||||
autoreconf -fi
|
||||
echo "./configure ${CONFIG_OPTS}"
|
||||
./configure ${CONFIG_OPTS}
|
||||
echo "::endgroup::"
|
||||
@@ -385,7 +349,7 @@ jobs:
|
||||
echo "::endgroup::"
|
||||
- name: cross-platform-action on ${{ matrix.cross_platform_os }} ${{ matrix.cross_platform_version }}
|
||||
if: ${{ matrix.with_cross_platform_action == 'yes' }}
|
||||
uses: cross-platform-actions/action@v0.25.0
|
||||
uses: cross-platform-actions/action@v1.0.0
|
||||
env:
|
||||
CROSS_PLATFORM_OS: ${{ matrix.cross_platform_os }}
|
||||
with:
|
||||
@@ -398,12 +362,10 @@ jobs:
|
||||
cpu_count: 2
|
||||
run: |
|
||||
set -e -x
|
||||
if test "$CROSS_PLATFORM_OS" = "freebsd"; then sudo pkg install -y autoconf automake libtool pkgconf openssl libevent expat; fi
|
||||
if test "$CROSS_PLATFORM_OS" = "openbsd"; then sudo pkg_add autoconf-2.71 automake-1.16.5 libtool pkgconf libevent; export AUTOCONF_VERSION="2.71"; export AUTOMAKE_VERSION="1.16"; fi
|
||||
if test "$CROSS_PLATFORM_OS" = "netbsd"; then sudo pkgin -y install autoconf automake libtool pkgconf libevent; export LDFLAGS="-Wl,--rpath=/usr/pkg/lib"; fi
|
||||
if test "$CROSS_PLATFORM_OS" = "freebsd"; then sudo pkg install -y openssl libevent expat; fi
|
||||
if test "$CROSS_PLATFORM_OS" = "openbsd"; then sudo pkg_add libevent; fi
|
||||
if test "$CROSS_PLATFORM_OS" = "netbsd"; then sudo pkgin -y install libevent; fi
|
||||
echo "::group::configure"
|
||||
rm -f aclocal.m4
|
||||
autoreconf -fi
|
||||
./configure ${{ matrix.cross_platform_config }}
|
||||
echo "::endgroup::"
|
||||
echo "::group::make"
|
||||
@@ -417,15 +379,10 @@ jobs:
|
||||
run: sudo apt-get install libevent-dev
|
||||
- name: install expat
|
||||
if: ${{ matrix.install_expat == 'yes' }}
|
||||
run: |
|
||||
brew install expat
|
||||
brew install autoconf automake libtool make
|
||||
run: brew install expat
|
||||
- name: configure
|
||||
if: ${{ matrix.config != 'no' }}
|
||||
run: |
|
||||
if test `uname` = "Linux"; then sudo apt-get install autoconf automake libtool make; fi
|
||||
autoreconf -fi
|
||||
./configure ${{ matrix.config }}
|
||||
run: ./configure ${{ matrix.config }}
|
||||
- name: make
|
||||
if: ${{ matrix.make != 'no' }}
|
||||
run: make
|
||||
|
||||
@@ -12,16 +12,11 @@ jobs:
|
||||
runs-on: ubuntu-latest
|
||||
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
- uses: actions/checkout@v7
|
||||
with:
|
||||
submodules: recursive
|
||||
persist-credentials: false
|
||||
- name: install packages
|
||||
run: sudo apt-get install autoconf automake libtool make
|
||||
- name: configure
|
||||
run: |
|
||||
autoreconf -fi
|
||||
./configure --enable-debug
|
||||
run: ./configure --enable-debug
|
||||
- name: make
|
||||
run: make
|
||||
- name: make test
|
||||
|
||||
@@ -3,17 +3,11 @@
|
||||
/.libs/
|
||||
/.source
|
||||
/Makefile
|
||||
/aclocal.m4
|
||||
/autom4te.cache/
|
||||
/config.guess
|
||||
/config.h
|
||||
/config.h.in
|
||||
/config.h.in~
|
||||
/config.log
|
||||
/config.status
|
||||
/config.sub
|
||||
/configure
|
||||
/configure~
|
||||
/dnstap/dnstap_config.h
|
||||
/dnscrypt/dnscrypt_config.h
|
||||
/util/configlexer.c
|
||||
@@ -28,10 +22,8 @@
|
||||
/doc/unbound-host.1
|
||||
/doc/unbound.8
|
||||
/doc/unbound.conf.5
|
||||
/install-sh
|
||||
/libtool
|
||||
/libunbound.la
|
||||
/ltmain.sh
|
||||
/_unbound.la
|
||||
/smallapp/unbound-control-setup.sh
|
||||
/unbound
|
||||
|
||||
@@ -1,3 +0,0 @@
|
||||
[submodule "simdzone"]
|
||||
path = simdzone
|
||||
url = https://github.com/NLnetLabs/simdzone.git
|
||||
+27
-54
@@ -56,7 +56,7 @@ YACC=@YACC@
|
||||
LEX=@LEX@
|
||||
STRIP=@STRIP@
|
||||
CC=@CC@
|
||||
CPPFLAGS=-I. @CPPFLAGS@ -Isimdzone/include -I@srcdir@/simdzone/include
|
||||
CPPFLAGS=-I. @CPPFLAGS@
|
||||
PYTHON_CPPFLAGS=-I. -I$(srcdir) @PYTHON_CPPFLAGS@
|
||||
CFLAGS=-DSRCDIR=$(srcdir) @CFLAGS@
|
||||
LDFLAGS=@LDFLAGS@
|
||||
@@ -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
|
||||
@@ -267,7 +268,6 @@ LIBUNBOUND_SRC=libunbound/context.c libunbound/libunbound.c \
|
||||
libunbound/libworker.c
|
||||
LIBUNBOUND_OBJ=context.lo libunbound.lo libworker.lo ub_event_pluggable.lo
|
||||
LIBUNBOUND_OBJ_LINK=$(LIBUNBOUND_OBJ) $(COMMON_OBJ_WITHOUT_UB_EVENT) $(SLDNS_OBJ) $(COMPAT_OBJ)
|
||||
SIMDZONE_OBJ=@SIMDZONE_OBJ@
|
||||
|
||||
# win apps or "" if not on windows
|
||||
WINAPPS=@WINAPPS@
|
||||
@@ -365,24 +365,19 @@ longtest: tests
|
||||
if test ! $(srcdir)/testdata -ef ./testdata; then rm -rf testcode testdata; mkdir testcode testdata; cp -R $(srcdir)/testdata/*.sh $(srcdir)/testdata/*.tdir $(srcdir)/testdata/*.rpl $(srcdir)/testdata/*.crpl testdata; cp $(srcdir)/testcode/*.sh testcode; if test ! -d util; then mkdir util; fi; cp $(srcdir)/util/iana_ports.inc util; fi
|
||||
if test -x "`which bash`"; then bash testcode/do-tests.sh; else sh testcode/do-tests.sh; fi
|
||||
|
||||
simdzone/libzone.la:
|
||||
$(MAKE) -C simdzone
|
||||
|
||||
simdzone/include/zone/export.h: simdzone/libzone.la
|
||||
|
||||
lib: libunbound.la unbound.h
|
||||
|
||||
libunbound.la: simdzone/libzone.la $(LIBUNBOUND_OBJ_LINK)
|
||||
$(LINK_LIB) $(UBSYMS) -o $@ $(LIBUNBOUND_OBJ_LINK) $(SIMDZONE_OBJ) -rpath $(libdir) $(SSLLIB) $(LIBS)
|
||||
libunbound.la: $(LIBUNBOUND_OBJ_LINK)
|
||||
$(LINK_LIB) $(UBSYMS) -o $@ $(LIBUNBOUND_OBJ_LINK) -rpath $(libdir) $(SSLLIB) $(LIBS)
|
||||
|
||||
unbound$(EXEEXT): $(DAEMON_OBJ_LINK) libunbound.la
|
||||
$(LINK) -o $@ $(DAEMON_OBJ_LINK) $(EXTRALINK) $(SIMDZONE_OBJ) $(SSLLIB) $(LIBS) $(DYNLIBMOD_EXTRALIBS)
|
||||
$(LINK) -o $@ $(DAEMON_OBJ_LINK) $(EXTRALINK) $(SSLLIB) $(LIBS) $(DYNLIBMOD_EXTRALIBS)
|
||||
|
||||
unbound-checkconf$(EXEEXT): $(CHECKCONF_OBJ_LINK) libunbound.la
|
||||
$(LINK) -o $@ $(CHECKCONF_OBJ_LINK) $(EXTRALINK) $(SIMDZONE_OBJ) $(SSLLIB) $(LIBS)
|
||||
$(LINK) -o $@ $(CHECKCONF_OBJ_LINK) $(EXTRALINK) $(SSLLIB) $(LIBS)
|
||||
|
||||
unbound-control$(EXEEXT): $(CONTROL_OBJ_LINK) libunbound.la
|
||||
$(LINK) -o $@ $(CONTROL_OBJ_LINK) $(EXTRALINK) $(SIMDZONE_OBJ) $(SSLLIB) $(LIBS)
|
||||
$(LINK) -o $@ $(CONTROL_OBJ_LINK) $(EXTRALINK) $(SSLLIB) $(LIBS)
|
||||
|
||||
unbound-host$(EXEEXT): $(HOST_OBJ_LINK) libunbound.la
|
||||
$(LINK) -o $@ $(HOST_OBJ_LINK) libunbound.la $(SSLLIB) $(LIBS)
|
||||
@@ -400,43 +395,43 @@ anchor-update$(EXEEXT): $(ANCHORUPD_OBJ_LINK) libunbound.la
|
||||
$(LINK) -o $@ $(ANCHORUPD_OBJ_LINK) libunbound.la $(LIBS)
|
||||
|
||||
unittest$(EXEEXT): $(UNITTEST_OBJ_LINK)
|
||||
$(LINK) -o $@ $(UNITTEST_OBJ_LINK) $(SIMDZONE_OBJ) $(SSLLIB) $(LIBS)
|
||||
$(LINK) -o $@ $(UNITTEST_OBJ_LINK) $(SSLLIB) $(LIBS)
|
||||
|
||||
testbound$(EXEEXT): $(TESTBOUND_OBJ_LINK)
|
||||
$(LINK) -o $@ $(TESTBOUND_OBJ_LINK) $(SIMDZONE_OBJ) $(SSLLIB) $(LIBS)
|
||||
$(LINK) -o $@ $(TESTBOUND_OBJ_LINK) $(SSLLIB) $(LIBS)
|
||||
|
||||
lock-verify$(EXEEXT): $(LOCKVERIFY_OBJ_LINK)
|
||||
$(LINK) -o $@ $(LOCKVERIFY_OBJ_LINK) $(SIMDZONE_OBJ) $(SSLLIB) $(LIBS)
|
||||
$(LINK) -o $@ $(LOCKVERIFY_OBJ_LINK) $(SSLLIB) $(LIBS)
|
||||
|
||||
petal$(EXEEXT): $(PETAL_OBJ_LINK)
|
||||
$(LINK) -o $@ $(PETAL_OBJ_LINK) $(SSLLIB) $(LIBS)
|
||||
|
||||
pktview$(EXEEXT): $(PKTVIEW_OBJ_LINK)
|
||||
$(LINK) -o $@ $(PKTVIEW_OBJ_LINK) $(SIMDZONE_OBJ) $(SSLLIB) $(LIBS)
|
||||
$(LINK) -o $@ $(PKTVIEW_OBJ_LINK) $(SSLLIB) $(LIBS)
|
||||
|
||||
memstats$(EXEEXT): $(MEMSTATS_OBJ_LINK)
|
||||
$(LINK) -o $@ $(MEMSTATS_OBJ_LINK) $(SIMDZONE_OBJ) $(SSLLIB) $(LIBS)
|
||||
$(LINK) -o $@ $(MEMSTATS_OBJ_LINK) $(SSLLIB) $(LIBS)
|
||||
|
||||
asynclook$(EXEEXT): $(ASYNCLOOK_OBJ_LINK) libunbound.la
|
||||
$(LINK) -o $@ $(ASYNCLOOK_OBJ_LINK) libunbound.la $(SSLLIB) $(LIBS)
|
||||
|
||||
streamtcp$(EXEEXT): $(STREAMTCP_OBJ_LINK)
|
||||
$(LINK) -o $@ $(STREAMTCP_OBJ_LINK) $(SIMDZONE_OBJ) $(SSLLIB) $(LIBS)
|
||||
$(LINK) -o $@ $(STREAMTCP_OBJ_LINK) $(SSLLIB) $(LIBS)
|
||||
|
||||
dohclient$(EXEEXT): $(DOHCLIENT_OBJ_LINK)
|
||||
$(LINK) -o $@ $(DOHCLIENT_OBJ_LINK) $(SIMDZONE_OBJ) $(SSLLIB) $(LIBS)
|
||||
$(LINK) -o $@ $(DOHCLIENT_OBJ_LINK) $(SSLLIB) $(LIBS)
|
||||
|
||||
doqclient$(EXEEXT): $(DOQCLIENT_OBJ_LINK)
|
||||
$(LINK) -o $@ $(DOQCLIENT_OBJ_LINK) $(SIMDZONE_OBJ) $(SSLLIB) $(LIBS)
|
||||
$(LINK) -o $@ $(DOQCLIENT_OBJ_LINK) $(SSLLIB) $(LIBS)
|
||||
|
||||
perf$(EXEEXT): $(PERF_OBJ_LINK)
|
||||
$(LINK) -o $@ $(PERF_OBJ_LINK) $(SIMDZONE_OBJ) $(SSLLIB) $(LIBS)
|
||||
$(LINK) -o $@ $(PERF_OBJ_LINK) $(SSLLIB) $(LIBS)
|
||||
|
||||
delayer$(EXEEXT): $(DELAYER_OBJ_LINK)
|
||||
$(LINK) -o $@ $(DELAYER_OBJ_LINK) $(SIMDZONE_OBJ) $(SSLLIB) $(LIBS)
|
||||
$(LINK) -o $@ $(DELAYER_OBJ_LINK) $(SSLLIB) $(LIBS)
|
||||
|
||||
readzone$(EXEEXT): $(READZONE_OBJ_LINK)
|
||||
$(LINK) -o $@ $(READZONE_OBJ_LINK) $(SIMDZONE_OBJ) $(SSLLIB) $(LIBS)
|
||||
$(LINK) -o $@ $(READZONE_OBJ_LINK) $(SSLLIB) $(LIBS)
|
||||
|
||||
signit$(EXEEXT): testcode/signit.c
|
||||
$(CC) $(CPPFLAGS) $(CFLAGS) @PTHREAD_CFLAGS_ONLY@ -o $@ testcode/signit.c $(LDFLAGS) -lldns $(SSLLIB) $(LIBS)
|
||||
@@ -464,7 +459,7 @@ dnstap/dnstap.pb-c.h: dnstap/dnstap.pb-c.c
|
||||
touch $@
|
||||
|
||||
unbound-dnstap-socket$(EXEEXT): $(DNSTAP_SOCKET_OBJ_LINK)
|
||||
$(LINK) -o $@ $(DNSTAP_SOCKET_OBJ_LINK) $(SIMDZONE_OBJ) $(SSLLIB) $(LIBS)
|
||||
$(LINK) -o $@ $(DNSTAP_SOCKET_OBJ_LINK) $(SSLLIB) $(LIBS)
|
||||
|
||||
dnstap.pb-c.lo dnstap.pb-c.o: dnstap/dnstap.pb-c.c dnstap/dnstap.pb-c.h
|
||||
dtstream.lo dtstream.o: $(srcdir)/dnstap/dtstream.c config.h $(srcdir)/dnstap/dtstream.h
|
||||
@@ -528,9 +523,7 @@ util/configparser.c: $(srcdir)/util/configparser.y
|
||||
util/configparser.h: util/configparser.c
|
||||
touch $@
|
||||
|
||||
.PHONY: .clean .distclean .maintainer-clean .realclean .devclean
|
||||
|
||||
.clean:
|
||||
clean:
|
||||
rm -f *.o *.d *.lo *~ tags
|
||||
rm -f unbound$(EXEEXT) unbound-checkconf$(EXEEXT) unbound-host$(EXEEXT) unbound-control$(EXEEXT) unbound-anchor$(EXEEXT) unbound-control-setup libunbound.la unbound.h
|
||||
rm -f $(ALL_SRC:.c=.lint)
|
||||
@@ -538,37 +531,19 @@ util/configparser.h: util/configparser.c
|
||||
rm -f libunbound.a
|
||||
rm -rf autom4te.cache .libs build doc/html doc/xml
|
||||
|
||||
.distclean: .clean
|
||||
distclean: clean
|
||||
rm -f config.status config.log config.h
|
||||
rm -f doc/example.conf doc/libunbound.3 doc/unbound-anchor.8 doc/unbound-checkconf.8 doc/unbound-control.8 doc/unbound.8 doc/unbound.conf.5 doc/unbound-host.1
|
||||
rm -f smallapp/unbound-control-setup.sh dnstap/dnstap_config.h dnscrypt/dnscrypt_config.h contrib/libunbound.pc contrib/unbound.socket contrib/unbound.service
|
||||
rm -f $(TEST_BIN)
|
||||
rm -f Makefile
|
||||
|
||||
.maintainer-clean: .distclean
|
||||
maintainer-clean: distclean
|
||||
rm -f util/configlexer.c util/configparser.c util/configparser.h
|
||||
|
||||
.realclean: .maintainer-clean
|
||||
realclean: maintainer-clean
|
||||
rm -f configure config.h.in config.sub config.guess ltmain.sh aclocal.m4 libtool
|
||||
|
||||
.devclean: .realclean
|
||||
rm -f config.h.in configure
|
||||
|
||||
clean: .clean
|
||||
$(MAKE) -C simdzone clean
|
||||
|
||||
distclean: .distclean
|
||||
$(MAKE) -C simdzone distclean
|
||||
|
||||
realclean: .realclean
|
||||
$(MAKE) -C simdzone realclean
|
||||
|
||||
maintainer-clean: .maintainer-clean
|
||||
$(MAKE) -C simdzone maintainer-clean
|
||||
|
||||
devclean: .devclean
|
||||
$(MAKE) -C simdzone devclean
|
||||
|
||||
.SUFFIXES: .lint
|
||||
.c.lint:
|
||||
$(LINT) $(LINTFLAGS) -I. -I$(srcdir) $<
|
||||
@@ -729,7 +704,6 @@ depend:
|
||||
-e 's?$$(srcdir)/edns-subnet/subnetmod.h $$(srcdir)/edns-subnet/subnet-whitelist.h $$(srcdir)/edns-subnet/edns-subnet.h $$(srcdir)/edns-subnet/addrtree.h?$$(SUBNET_HEADER)?g' \
|
||||
-e 's?$$(srcdir)/ipsecmod/ipsecmod.h $$(srcdir)/ipsecmod/ipsecmod-whitelist.h?$$(IPSECMOD_HEADER)?g' \
|
||||
-e 's?$$(srcdir)/dynlibmod/dynlibmod.h?$$(DYNLIBMOD_HEADER)?g' \
|
||||
-e 's?$$(srcdir)/simdzone/include/zone/export.h?simdzone/include/zone/export.h?g' \
|
||||
-e 's!\(.*\)\.o[ :]*!\1.lo \1.o: !g' \
|
||||
> $(DEPEND_TMP)
|
||||
cp $(DEPEND_TARGET) $(DEPEND_TMP2)
|
||||
@@ -748,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 \
|
||||
@@ -1027,9 +1002,7 @@ authzone.lo authzone.o: $(srcdir)/services/authzone.c config.h $(srcdir)/service
|
||||
$(srcdir)/services/listen_dnsport.h $(srcdir)/daemon/acl_list.h \
|
||||
$(srcdir)/sldns/str2wire.h $(srcdir)/sldns/wire2str.h $(srcdir)/sldns/parseutil.h $(srcdir)/sldns/keyraw.h \
|
||||
$(srcdir)/validator/val_nsec3.h $(srcdir)/validator/val_nsec.h $(srcdir)/validator/val_secalgo.h \
|
||||
$(srcdir)/validator/val_sigcrypt.h $(srcdir)/validator/val_anchor.h $(srcdir)/validator/val_utils.h \
|
||||
$(srcdir)/simdzone/include/zone.h $(srcdir)/simdzone/include/zone/attributes.h \
|
||||
simdzone/include/zone/export.h
|
||||
$(srcdir)/validator/val_sigcrypt.h $(srcdir)/validator/val_anchor.h $(srcdir)/validator/val_utils.h
|
||||
fptr_wlist.lo fptr_wlist.o: $(srcdir)/util/fptr_wlist.c config.h $(srcdir)/util/fptr_wlist.h \
|
||||
$(srcdir)/util/netevent.h $(srcdir)/dnscrypt/dnscrypt.h \
|
||||
$(srcdir)/dnscrypt/cert.h $(srcdir)/util/locks.h $(srcdir)/util/log.h \
|
||||
|
||||
@@ -1,5 +1,4 @@
|
||||
Unbound README
|
||||
* From source repository: git submodule update --init && autoreconf -fi
|
||||
* ./configure && make && make install
|
||||
* You can use libevent if you want. libevent is useful when using
|
||||
many (10000) outgoing ports. By default max 256 ports are opened at
|
||||
|
||||
@@ -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/).
|
||||
|
||||
@@ -19,14 +19,6 @@ You can learn more about Unbound by reading our
|
||||
Make sure you have the C toolchain, OpenSSL and its include files, and libexpat
|
||||
installed.
|
||||
If building from the repository source you also need flex and bison installed.
|
||||
If building from the repository source, also init the git submodule and
|
||||
create the configure script with:
|
||||
|
||||
```
|
||||
git submodule update --init
|
||||
autoreconf -fi
|
||||
```
|
||||
|
||||
Unbound can be compiled and installed using:
|
||||
|
||||
```
|
||||
|
||||
Vendored
+9440
File diff suppressed because it is too large
Load Diff
+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"
|
||||
;;
|
||||
|
||||
|
||||
+22
-4
@@ -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)
|
||||
@@ -754,8 +760,10 @@ cachedb_intcache_store(struct module_qstate* qstate, int msg_expired,
|
||||
"(original ttl: %d)", (int)original_ttl);
|
||||
/* The expired entry does not get checked by the validator
|
||||
* and we need a validation value for it. */
|
||||
/* By setting this to unchecked, bogus data is not returned
|
||||
* as non-bogus. */
|
||||
if(qstate->env->cfg->cachedb_check_when_serve_expired)
|
||||
qstate->return_msg->rep->security = sec_status_insecure;
|
||||
qstate->return_msg->rep->security = sec_status_unchecked;
|
||||
}
|
||||
(void)dns_cache_store(qstate->env, &qstate->qinfo,
|
||||
qstate->return_msg->rep, 0, qstate->prefetch_leeway, 0,
|
||||
@@ -803,8 +811,11 @@ cachedb_handle_query(struct module_qstate* qstate,
|
||||
return;
|
||||
}
|
||||
|
||||
if(qstate->blacklist || qstate->no_cache_lookup) {
|
||||
/* cache is blacklisted or we are instructed from edns to not look */
|
||||
if(qstate->blacklist || qstate->no_cache_lookup
|
||||
|| iter_stub_fwd_no_cache(qstate, &qstate->qinfo, NULL, NULL,
|
||||
NULL, 0)) {
|
||||
/* cache is blacklisted or we are instructed from edns to not
|
||||
* look or a forwarder/stub forbids it */
|
||||
/* pass request to next module */
|
||||
qstate->ext_state[id] = module_wait_module;
|
||||
return;
|
||||
@@ -858,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 */
|
||||
@@ -892,7 +908,9 @@ cachedb_handle_response(struct module_qstate* qstate,
|
||||
{
|
||||
qstate->is_cachedb_answer = 0;
|
||||
/* check if we are not enabled or instructed to not cache, and skip */
|
||||
if(!ie->enabled || qstate->no_cache_store) {
|
||||
if(!ie->enabled || qstate->no_cache_store
|
||||
|| iter_stub_fwd_no_cache(qstate, &qstate->qinfo, NULL, NULL,
|
||||
NULL, 0)) {
|
||||
/* we are done with the query */
|
||||
qstate->ext_state[id] = module_finished;
|
||||
return;
|
||||
|
||||
@@ -48,8 +48,8 @@ typedef struct
|
||||
a = PLUS(a,b); d = ROTATE(XOR(d,a), 8); \
|
||||
c = PLUS(c,d); b = ROTATE(XOR(b,c), 7);
|
||||
|
||||
static const char sigma[16] = "expand 32-byte k";
|
||||
static const char tau[16] = "expand 16-byte k";
|
||||
static const char ATTR_NONSTRING(sigma[16]) = "expand 32-byte k";
|
||||
static const char ATTR_NONSTRING(tau[16]) = "expand 16-byte k";
|
||||
|
||||
static void
|
||||
chacha_keysetup(chacha_ctx *x,const u8 *k,u32 kbits,u32 ATTR_UNUSED(ivbits))
|
||||
|
||||
+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;
|
||||
}
|
||||
|
||||
+1
-4
@@ -42,10 +42,7 @@ static const int year_lengths[2] = {
|
||||
};
|
||||
|
||||
static void
|
||||
timesub(timep, offset, tmp)
|
||||
const time_t * const timep;
|
||||
const long offset;
|
||||
struct tm * const tmp;
|
||||
timesub(const time_t * const timep, const long offset, struct tm * const tmp)
|
||||
{
|
||||
long days;
|
||||
long rem;
|
||||
|
||||
+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";
|
||||
|
||||
+1812
File diff suppressed because it is too large
Load Diff
+1707
File diff suppressed because it is too large
Load Diff
+1971
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
+111
-46
@@ -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],[24])
|
||||
m4_define([VERSION_MICRO],[3])
|
||||
m4_define([VERSION_MINOR],[26])
|
||||
m4_define([VERSION_MICRO],[1])
|
||||
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=36
|
||||
LIBUNBOUND_REVISION=40
|
||||
LIBUNBOUND_AGE=1
|
||||
# 1.0.0 had 0:12:0
|
||||
# 1.0.1 had 0:13:0
|
||||
@@ -122,7 +122,11 @@ LIBUNBOUND_AGE=1
|
||||
# 1.24.0 had 9:33:1
|
||||
# 1.24.1 had 9:34:1
|
||||
# 1.24.2 had 9:35:1
|
||||
# 1.24.3 had 9:36: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
|
||||
|
||||
# Current -- the number of the binary API that we're implementing
|
||||
# Revision -- which iteration of the implementation of the binary
|
||||
@@ -177,12 +181,6 @@ else
|
||||
else on_mingw="no"; fi
|
||||
fi
|
||||
|
||||
dnl install the install-sh file with libtoolize -ci, and autoreconf -fi.
|
||||
AC_REQUIRE_AUX_FILE([install-sh])
|
||||
if test ! -f install-sh; then
|
||||
AC_MSG_WARN([./install-sh is missing, use `libtoolize -ci` or `autoreconf -fi` to add it])
|
||||
fi
|
||||
|
||||
#
|
||||
# Determine configuration file
|
||||
# the eval is to evaluate shell expansion twice
|
||||
@@ -487,7 +485,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],,, [
|
||||
@@ -737,6 +735,76 @@ int main(void) {return 0;}
|
||||
])
|
||||
fi
|
||||
|
||||
if test x_$ub_have_pthreads != x_no; then
|
||||
# Long checks to support pthread_setname_np().
|
||||
# Some OSes have the extra non-portable functions in a specific
|
||||
# header file.
|
||||
AC_CHECK_HEADERS([pthread_np.h],,, [AC_INCLUDES_DEFAULT])
|
||||
BAKCFLAGS="$CFLAGS"
|
||||
CFLAGS="$CFLAGS -Werror"
|
||||
# MacOS only has 1 argument, the name.
|
||||
AC_MSG_CHECKING([whether pthread_setname_np has only 1 argument])
|
||||
AC_COMPILE_IFELSE([AC_LANG_PROGRAM([AC_INCLUDES_DEFAULT
|
||||
#include <pthread.h>
|
||||
#ifdef HAVE_PTHREAD_NP_H
|
||||
#include <pthread_np.h>
|
||||
#endif
|
||||
],[
|
||||
(void)pthread_setname_np("");
|
||||
])],[
|
||||
AC_MSG_RESULT(yes)
|
||||
AC_DEFINE(HAVE_PTHREAD_SETNAME_NP1, 1, [Define if pthread_setname_np has only 1 argument.])
|
||||
],[
|
||||
AC_MSG_RESULT(no)
|
||||
])
|
||||
# NetBSD has 3 arguments to allow for formatting of the name.
|
||||
AC_MSG_CHECKING([whether pthread_setname_np has 3 arguments])
|
||||
AC_COMPILE_IFELSE([AC_LANG_PROGRAM([AC_INCLUDES_DEFAULT
|
||||
#include <pthread.h>
|
||||
#ifdef HAVE_PTHREAD_NP_H
|
||||
#include <pthread_np.h>
|
||||
#endif
|
||||
],[
|
||||
(void)pthread_setname_np(0, "", NULL);
|
||||
])],[
|
||||
AC_MSG_RESULT(yes)
|
||||
AC_DEFINE(HAVE_PTHREAD_SETNAME_NP3, 1, [Define if pthread_setname_np has 3 arguments.])
|
||||
],[
|
||||
AC_MSG_RESULT(no)
|
||||
])
|
||||
# Most OSes have the common 2 arguments, thread and name.
|
||||
AC_MSG_CHECKING([whether pthread_setname_np has the common 2 arguments])
|
||||
AC_COMPILE_IFELSE([AC_LANG_PROGRAM([AC_INCLUDES_DEFAULT
|
||||
#include <pthread.h>
|
||||
#ifdef HAVE_PTHREAD_NP_H
|
||||
#include <pthread_np.h>
|
||||
#endif
|
||||
],[
|
||||
(void)pthread_setname_np(0, "");
|
||||
])],[
|
||||
AC_MSG_RESULT(yes)
|
||||
AC_DEFINE(HAVE_PTHREAD_SETNAME_NP, 1, [Define if pthread_setname_np has the common 2 arguments.])
|
||||
],[
|
||||
AC_MSG_RESULT(no)
|
||||
])
|
||||
# FreeBSD/OpenBSD use a slightly different function name.
|
||||
AC_MSG_CHECKING([whether pthread_setname_np exists as pthread_set_name_np instead])
|
||||
AC_COMPILE_IFELSE([AC_LANG_PROGRAM([AC_INCLUDES_DEFAULT
|
||||
#include <pthread.h>
|
||||
#ifdef HAVE_PTHREAD_NP_H
|
||||
#include <pthread_np.h>
|
||||
#endif
|
||||
],[
|
||||
(void)pthread_set_name_np(0, "");
|
||||
])],[
|
||||
AC_MSG_RESULT(yes)
|
||||
AC_DEFINE(HAVE_PTHREAD_SET_NAME_NP, 1, [Define if pthread_setname_np exists as pthread_set_name_np instead.])
|
||||
],[
|
||||
AC_MSG_RESULT(no)
|
||||
])
|
||||
CFLAGS="$BAKCFLAGS"
|
||||
fi
|
||||
|
||||
# check solaris thread library
|
||||
AC_ARG_WITH(solaris-threads, AS_HELP_STRING([--with-solaris-threads],[use solaris native thread library.]), [ ],[ withval="no" ])
|
||||
ub_have_sol_threads=no
|
||||
@@ -1014,12 +1082,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], [], [], [
|
||||
@@ -1638,6 +1713,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" ])
|
||||
@@ -1649,6 +1727,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
|
||||
@@ -1670,6 +1749,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
|
||||
@@ -1775,6 +1870,7 @@ if test $ac_cv_func_daemon = yes; then
|
||||
])
|
||||
fi
|
||||
|
||||
AC_CHECK_MEMBERS([struct stat.st_mtimensec, struct stat.st_mtim.tv_nsec])
|
||||
AC_CHECK_MEMBERS([struct sockaddr_un.sun_len],,,[
|
||||
AC_INCLUDES_DEFAULT
|
||||
#ifdef HAVE_SYS_UN_H
|
||||
@@ -1845,7 +1941,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])])
|
||||
|
||||
@@ -2042,9 +2138,6 @@ dt_DNSTAP([$UNBOUND_RUN_DIR/dnstap.sock],
|
||||
AC_SUBST([ENABLE_DNSTAP], [0])
|
||||
]
|
||||
)
|
||||
dnstap_config="dnstap/dnstap_config.h.tmp:dnstap/dnstap_config.h.in"
|
||||
dnstap_config_tmp="dnstap/dnstap_config.h.tmp"
|
||||
dnstap_config_out="dnstap/dnstap_config.h"
|
||||
|
||||
# check for dnscrypt if requested
|
||||
dnsc_DNSCRYPT([
|
||||
@@ -2499,34 +2592,6 @@ AC_SUBST(version, [VERSION_MAJOR.VERSION_MINOR.VERSION_MICRO])
|
||||
AX_BUILD_DATE_EPOCH(date, [[%b %e, %Y]])
|
||||
AC_SUBST(date)
|
||||
|
||||
AC_CONFIG_FILES([Makefile doc/example.conf doc/libunbound.3 doc/unbound.8 doc/unbound-anchor.8 doc/unbound-checkconf.8 doc/unbound.conf.5 doc/unbound-control.8 doc/unbound-host.1 smallapp/unbound-control-setup.sh $dnstap_config dnscrypt/dnscrypt_config.h contrib/libunbound.pc contrib/unbound.socket contrib/unbound.service contrib/unbound_portable.service])
|
||||
AC_CONFIG_FILES([Makefile doc/example.conf doc/libunbound.3 doc/unbound.8 doc/unbound-anchor.8 doc/unbound-checkconf.8 doc/unbound.conf.5 doc/unbound-control.8 doc/unbound-host.1 smallapp/unbound-control-setup.sh dnstap/dnstap_config.h dnscrypt/dnscrypt_config.h contrib/libunbound.pc contrib/unbound.socket contrib/unbound.service contrib/unbound_portable.service])
|
||||
AC_CONFIG_HEADERS([config.h])
|
||||
|
||||
# Arguments introduced specifically for simdzone.
|
||||
AC_ARG_ENABLE(westmere, AS_HELP_STRING([--disable-westmere], [Disable Westmere (SSE4.2) parser kernel]))
|
||||
AC_ARG_ENABLE(haswell, AS_HELP_STRING([--disable-haswell], [Disable Haswell (AVX2) parser kernel]))
|
||||
if test ! -f simdzone/configure.ac; then AC_MSG_ERROR([There is no "simdzone/configure.ac" file. The simdzone directory has not been fetched, perhaps get it with 'git submodule update --init'.]); fi
|
||||
if test ! -f simdzone/configure; then AC_MSG_ERROR([There is no "simdzone/configure" file. The simdzone directory has no configure script file, perhaps run 'autoreconf -fi'.]); fi
|
||||
AC_CONFIG_SUBDIRS([simdzone])
|
||||
|
||||
AC_OUTPUT
|
||||
# Pick up the objects for simdzone.
|
||||
SIMDZONE_OBJ=`(cd simdzone; make list_objs) | sed -e 's?src?simdzone/src?g'`
|
||||
AC_SUBST(SIMDZONE_OBJ)
|
||||
sed -e 's?^SIMDZONE_OBJ=.*$?SIMDZONE_OBJ='"$SIMDZONE_OBJ"'?' < Makefile > Makefile.tmp.$$
|
||||
mv -f Makefile.tmp.$$ Makefile
|
||||
# If dnstap config has changed, overwrite it.
|
||||
if test -n "$dnstap_config"; then
|
||||
if test ! -f "$dnstap_config_out"; then
|
||||
mv "$dnstap_config_tmp" "$dnstap_config_out" || AC_MSG_ERROR([Could not create $dnstap_config_out])
|
||||
else if diff "$dnstap_config_out" "$dnstap_config_tmp" >/dev/null 2>&1; then
|
||||
if test "x$opt_dnstap" != "xno"; then
|
||||
AC_MSG_NOTICE([In $srcdir: $dnstap_config_out is unchanged])
|
||||
fi
|
||||
rm -f "$dnstap_config_tmp"
|
||||
else
|
||||
rm -f "$dnstap_config_out"
|
||||
mv "$dnstap_config_tmp" "$dnstap_config_out" || AC_MSG_ERROR([Could not create $dnstap_config_out])
|
||||
fi
|
||||
fi
|
||||
fi
|
||||
|
||||
@@ -58,3 +58,5 @@ distribution but may be helpful.
|
||||
* unbound.init_yocto: An init script to start and stop the server. Put it
|
||||
in /etc/init.d/unbound to use it. It is for the Yocto Project, in
|
||||
embedded systems, contributed by beni-sandu.
|
||||
* gost12.patch: adds ECC-GOST12 support for the informational RFC9558.
|
||||
Contributed by Igor V. Ruzanov.
|
||||
|
||||
@@ -0,0 +1,325 @@
|
||||
diff --git a/sldns/keyraw.c b/sldns/keyraw.c
|
||||
index 42a9262a3..cc6406a56 100644
|
||||
--- a/sldns/keyraw.c
|
||||
+++ b/sldns/keyraw.c
|
||||
@@ -85,7 +85,7 @@ sldns_rr_dnskey_key_size_raw(const unsigned char* keydata,
|
||||
}
|
||||
break;
|
||||
#ifdef USE_GOST
|
||||
- case LDNS_ECC_GOST:
|
||||
+ case LDNS_ECC_GOST12:
|
||||
return 512;
|
||||
#endif
|
||||
#ifdef USE_ECDSA
|
||||
@@ -146,7 +146,7 @@ sldns_key_EVP_load_gost_id(void)
|
||||
if(gost_id) return gost_id;
|
||||
|
||||
/* see if configuration loaded gost implementation from other engine*/
|
||||
- meth = EVP_PKEY_asn1_find_str(NULL, "gost2001", -1);
|
||||
+ meth = EVP_PKEY_asn1_find_str(NULL, "gost2012_256", -1);
|
||||
if(meth) {
|
||||
EVP_PKEY_asn1_get0_info(&gost_id, NULL, NULL, NULL, NULL, meth);
|
||||
return gost_id;
|
||||
@@ -170,7 +170,7 @@ sldns_key_EVP_load_gost_id(void)
|
||||
return 0;
|
||||
}
|
||||
|
||||
- meth = EVP_PKEY_asn1_find_str(&e, "gost2001", -1);
|
||||
+ meth = EVP_PKEY_asn1_find_str(&e, "gost2012_256", -1);
|
||||
if(!meth) {
|
||||
/* algo not found */
|
||||
ENGINE_finish(e);
|
||||
@@ -536,12 +536,17 @@ EVP_PKEY* sldns_key_rsa2pkey_raw(unsigned char* key, size_t len)
|
||||
EVP_PKEY*
|
||||
sldns_gost2pkey_raw(unsigned char* key, size_t keylen)
|
||||
{
|
||||
- /* prefix header for X509 encoding */
|
||||
- uint8_t asn[37] = { 0x30, 0x63, 0x30, 0x1c, 0x06, 0x06, 0x2a, 0x85,
|
||||
- 0x03, 0x02, 0x02, 0x13, 0x30, 0x12, 0x06, 0x07, 0x2a, 0x85,
|
||||
- 0x03, 0x02, 0x02, 0x23, 0x01, 0x06, 0x07, 0x2a, 0x85, 0x03,
|
||||
- 0x02, 0x02, 0x1e, 0x01, 0x03, 0x43, 0x00, 0x04, 0x40};
|
||||
- unsigned char encoded[37+64];
|
||||
+ /* prefix header for X509 encoding
|
||||
+ *
|
||||
+ * note: based on draft-makarenko-gost2012-dnssec-01 (pre-RFC9558 and it DOES work!)
|
||||
+ * ASN1 header described in RFC9558 is not suitable due to d2i_PUBKEY() works with
|
||||
+ * non-compressed public keys (two additional bytes 0x04, 0x40 at the end of header)
|
||||
+ */
|
||||
+ uint8_t asn[32] = { 0x30, 0x5e, 0x30, 0x17, 0x06, 0x08, 0x2a, 0x85,
|
||||
+ 0x03, 0x07, 0x01, 0x01, 0x01, 0x01, 0x30, 0x0b,
|
||||
+ 0x06, 0x09, 0x2a, 0x85, 0x03, 0x07, 0x01, 0x02,
|
||||
+ 0x01, 0x01, 0x01, 0x03, 0x43, 0x00, 0x04, 0x40 };
|
||||
+ unsigned char encoded[32+64];
|
||||
const unsigned char* pp;
|
||||
if(keylen != 64) {
|
||||
/* key wrong size */
|
||||
@@ -549,8 +554,8 @@ sldns_gost2pkey_raw(unsigned char* key, size_t keylen)
|
||||
}
|
||||
|
||||
/* create evp_key */
|
||||
- memmove(encoded, asn, 37);
|
||||
- memmove(encoded+37, key, 64);
|
||||
+ memmove(encoded, asn, 32);
|
||||
+ memmove(encoded+32, key, 64);
|
||||
pp = (unsigned char*)&encoded[0];
|
||||
|
||||
return d2i_PUBKEY(NULL, &pp, (int)sizeof(encoded));
|
||||
diff --git a/sldns/rrdef.h b/sldns/rrdef.h
|
||||
index bbc3d5b86..7d5f3c057 100644
|
||||
--- a/sldns/rrdef.h
|
||||
+++ b/sldns/rrdef.h
|
||||
@@ -384,11 +384,12 @@ enum sldns_enum_algorithm
|
||||
LDNS_RSASHA1_NSEC3 = 7,
|
||||
LDNS_RSASHA256 = 8, /* RFC 5702 */
|
||||
LDNS_RSASHA512 = 10, /* RFC 5702 */
|
||||
- LDNS_ECC_GOST = 12, /* RFC 5933 */
|
||||
+ LDNS_ECC_GOST = 12, /* RFC 5933, deprecated */
|
||||
LDNS_ECDSAP256SHA256 = 13, /* RFC 6605 */
|
||||
LDNS_ECDSAP384SHA384 = 14, /* RFC 6605 */
|
||||
LDNS_ED25519 = 15, /* RFC 8080 */
|
||||
LDNS_ED448 = 16, /* RFC 8080 */
|
||||
+ LDNS_ECC_GOST12 = 23, /* RFC 9558 */
|
||||
LDNS_INDIRECT = 252,
|
||||
LDNS_PRIVATEDNS = 253,
|
||||
LDNS_PRIVATEOID = 254
|
||||
@@ -402,8 +403,9 @@ enum sldns_enum_hash
|
||||
{
|
||||
LDNS_SHA1 = 1, /* RFC 4034 */
|
||||
LDNS_SHA256 = 2, /* RFC 4509 */
|
||||
- LDNS_HASH_GOST = 3, /* RFC 5933 */
|
||||
- LDNS_SHA384 = 4 /* RFC 6605 */
|
||||
+ LDNS_HASH_GOST = 3, /* RFC 5933, deprecated */
|
||||
+ LDNS_SHA384 = 4, /* RFC 6605 */
|
||||
+ LDNS_HASH_GOST12 = 5 /* RFC 9558 */
|
||||
};
|
||||
typedef enum sldns_enum_hash sldns_hash;
|
||||
|
||||
diff --git a/sldns/wire2str.c b/sldns/wire2str.c
|
||||
index 75b8f37b0..b4c4755e6 100644
|
||||
--- a/sldns/wire2str.c
|
||||
+++ b/sldns/wire2str.c
|
||||
@@ -45,11 +45,12 @@ static sldns_lookup_table sldns_algorithms_data[] = {
|
||||
{ LDNS_RSASHA1_NSEC3, "RSASHA1-NSEC3-SHA1" },
|
||||
{ LDNS_RSASHA256, "RSASHA256"},
|
||||
{ LDNS_RSASHA512, "RSASHA512"},
|
||||
- { LDNS_ECC_GOST, "ECC-GOST"},
|
||||
+ { LDNS_ECC_GOST, "ECC-GOST"}, /* deprecated */
|
||||
{ LDNS_ECDSAP256SHA256, "ECDSAP256SHA256"},
|
||||
{ LDNS_ECDSAP384SHA384, "ECDSAP384SHA384"},
|
||||
{ LDNS_ED25519, "ED25519"},
|
||||
{ LDNS_ED448, "ED448"},
|
||||
+ { LDNS_ECC_GOST12, "ECC-GOST12"},
|
||||
{ LDNS_INDIRECT, "INDIRECT" },
|
||||
{ LDNS_PRIVATEDNS, "PRIVATEDNS" },
|
||||
{ LDNS_PRIVATEOID, "PRIVATEOID" },
|
||||
@@ -61,8 +62,9 @@ sldns_lookup_table* sldns_algorithms = sldns_algorithms_data;
|
||||
static sldns_lookup_table sldns_hashes_data[] = {
|
||||
{ LDNS_SHA1, "SHA1" },
|
||||
{ LDNS_SHA256, "SHA256" },
|
||||
- { LDNS_HASH_GOST, "HASH-GOST" },
|
||||
+ { LDNS_HASH_GOST, "HASH-GOST" }, /* deprecated */
|
||||
{ LDNS_SHA384, "SHA384" },
|
||||
+ { LDNS_HASH_GOST12, "HASH-GOST12" },
|
||||
{ 0, NULL }
|
||||
};
|
||||
sldns_lookup_table* sldns_hashes = sldns_hashes_data;
|
||||
diff --git a/testcode/unitverify.c b/testcode/unitverify.c
|
||||
index fcf2e2ffe..4a33e9f6a 100644
|
||||
--- a/testcode/unitverify.c
|
||||
+++ b/testcode/unitverify.c
|
||||
@@ -696,7 +696,7 @@ verify_test(void)
|
||||
#endif
|
||||
#ifdef USE_GOST
|
||||
if(sldns_key_EVP_load_gost_id())
|
||||
- verifytest_file(SRCDIRSTR "/testdata/test_sigs.gost", "20090807060504");
|
||||
+ verifytest_file(SRCDIRSTR "/testdata/test_sigs.gost12", "20251226060504");
|
||||
else printf("Warning: skipped GOST, openssl does not provide gost.\n");
|
||||
#endif
|
||||
#ifdef USE_ECDSA
|
||||
diff --git a/testdata/test_sigs.gost12 b/testdata/test_sigs.gost12
|
||||
new file mode 100644
|
||||
index 000000000..72a250cff
|
||||
--- /dev/null
|
||||
+++ b/testdata/test_sigs.gost12
|
||||
@@ -0,0 +1,39 @@
|
||||
+; Signature test file
|
||||
+
|
||||
+; first entry is a DNSKEY answer, with the DNSKEY rrset used for verification.
|
||||
+; later entries are verified with it.
|
||||
+
|
||||
+; Test GOST signatures using algo number 23.
|
||||
+
|
||||
+ENTRY_BEGIN
|
||||
+SECTION QUESTION
|
||||
+nlnetlabs.nl. IN DNSKEY
|
||||
+SECTION ANSWER
|
||||
+nlnetlabs.nl. 3600 IN DNSKEY 256 3 23 cdOtkEcb6NhcdOpIbPYtWyWxdlUiKgtKQbYg3lIjtG7i3fYjUID9zyOgoQEiV9wuGCfrw5cNsnvNw+8HiVFK4g== ;{id = 12301 (zsk), size = 512b}
|
||||
+ENTRY_END
|
||||
+
|
||||
+; entry to test
|
||||
+ENTRY_BEGIN
|
||||
+SECTION QUESTION
|
||||
+open.nlnetlabs.nl. IN A
|
||||
+SECTION ANSWER
|
||||
+open.nlnetlabs.nl. 600 IN A 213.154.224.1
|
||||
+open.nlnetlabs.nl. 600 IN RRSIG A 23 3 600 20260122084903 20251225084903 12301 nlnetlabs.nl. I12wYNs96DxMy26CWx296/sWMJAFg4nNXBo0sw7PnuMbJW5NFAmZYtFWhUdOWn4umaiodYOAmKG8Zg/OKvEtAQ==
|
||||
+ENTRY_END
|
||||
+
|
||||
+ENTRY_BEGIN
|
||||
+SECTION QUESTION
|
||||
+open.nlnetlabs.nl. IN AAAA
|
||||
+SECTION ANSWER
|
||||
+open.nlnetlabs.nl. 600 IN AAAA 2001:7b8:206:1::1
|
||||
+open.nlnetlabs.nl. 600 IN AAAA 2001:7b8:206:1::53
|
||||
+open.nlnetlabs.nl. 600 IN RRSIG AAAA 23 3 600 20260122084903 20251225084903 12301 nlnetlabs.nl. J0jHa+CP8HM6UDa2+uYgaze2mfpJTh2hkZ2KwMTYb5sfL6iBmxxql0c/403Itk4fMfYBMGn7zfzDQ+CxnCgSWw==
|
||||
+ENTRY_END
|
||||
+
|
||||
+ENTRY_BEGIN
|
||||
+SECTION QUESTION
|
||||
+open.nlnetlabs.nl. IN NSEC
|
||||
+SECTION ANSWER
|
||||
+open.nlnetlabs.nl. 86400 IN NSEC nlnetlabs.nl. A AAAA RRSIG NSEC
|
||||
+open.nlnetlabs.nl. 86400 IN RRSIG NSEC 23 3 86400 20260122084903 20251225084903 12301 nlnetlabs.nl. INCLYe9vAaNYaYx5Ay3Q6QdX+wPW9sMRvVlGt/jUEGgCi+88QlV80CT1oHrhRI66I14Wk6NRAGZRNx1tUPSHSg==
|
||||
+ENTRY_END
|
||||
diff --git a/validator/val_secalgo.c b/validator/val_secalgo.c
|
||||
index be8347b1b..4f621a309 100644
|
||||
--- a/validator/val_secalgo.c
|
||||
+++ b/validator/val_secalgo.c
|
||||
@@ -246,10 +246,10 @@ ds_digest_size_supported(int algo)
|
||||
return SHA256_DIGEST_LENGTH;
|
||||
#endif
|
||||
#ifdef USE_GOST
|
||||
- case LDNS_HASH_GOST:
|
||||
+ case LDNS_HASH_GOST12:
|
||||
/* we support GOST if it can be loaded */
|
||||
(void)sldns_key_EVP_load_gost_id();
|
||||
- if(EVP_get_digestbyname("md_gost94"))
|
||||
+ if(EVP_get_digestbyname("md_gost12_256"))
|
||||
return 32;
|
||||
else return 0;
|
||||
#endif
|
||||
@@ -265,9 +265,9 @@ ds_digest_size_supported(int algo)
|
||||
#ifdef USE_GOST
|
||||
/** Perform GOST hash */
|
||||
static int
|
||||
-do_gost94(unsigned char* data, size_t len, unsigned char* dest)
|
||||
+do_gost12(unsigned char* data, size_t len, unsigned char* dest)
|
||||
{
|
||||
- const EVP_MD* md = EVP_get_digestbyname("md_gost94");
|
||||
+ const EVP_MD* md = EVP_get_digestbyname("md_gost12_256");
|
||||
if(!md)
|
||||
return 0;
|
||||
return sldns_digest_evp(data, (unsigned int)len, dest, md);
|
||||
@@ -302,8 +302,8 @@ secalgo_ds_digest(int algo, unsigned char* buf, size_t len,
|
||||
return 1;
|
||||
#endif
|
||||
#ifdef USE_GOST
|
||||
- case LDNS_HASH_GOST:
|
||||
- if(do_gost94(buf, len, res))
|
||||
+ case LDNS_HASH_GOST12:
|
||||
+ if(do_gost12(buf, len, res))
|
||||
return 1;
|
||||
break;
|
||||
#endif
|
||||
@@ -384,7 +384,7 @@ dnskey_algo_id_is_supported(int id)
|
||||
#endif
|
||||
|
||||
#ifdef USE_GOST
|
||||
- case LDNS_ECC_GOST:
|
||||
+ case LDNS_ECC_GOST12:
|
||||
/* we support GOST if it can be loaded */
|
||||
return sldns_key_EVP_load_gost_id();
|
||||
#endif
|
||||
@@ -612,17 +612,17 @@ setup_key_digest(int algo, EVP_PKEY** evp_key, const EVP_MD** digest_type,
|
||||
|
||||
break;
|
||||
#ifdef USE_GOST
|
||||
- case LDNS_ECC_GOST:
|
||||
+ case LDNS_ECC_GOST12:
|
||||
*evp_key = sldns_gost2pkey_raw(key, keylen);
|
||||
if(!*evp_key) {
|
||||
verbose(VERB_QUERY, "verify: "
|
||||
"sldns_gost2pkey_raw failed");
|
||||
return 0;
|
||||
}
|
||||
- *digest_type = EVP_get_digestbyname("md_gost94");
|
||||
+ *digest_type = EVP_get_digestbyname("md_gost12_256");
|
||||
if(!*digest_type) {
|
||||
verbose(VERB_QUERY, "verify: "
|
||||
- "EVP_getdigest md_gost94 failed");
|
||||
+ "EVP_getdigest md_gost12_256 failed");
|
||||
return 0;
|
||||
}
|
||||
break;
|
||||
@@ -964,7 +964,7 @@ ds_digest_size_supported(int algo)
|
||||
return SHA384_LENGTH;
|
||||
#endif
|
||||
/* GOST not supported in NSS */
|
||||
- case LDNS_HASH_GOST:
|
||||
+ case LDNS_HASH_GOST12:
|
||||
default: break;
|
||||
}
|
||||
return 0;
|
||||
@@ -991,7 +991,7 @@ secalgo_ds_digest(int algo, unsigned char* buf, size_t len,
|
||||
return HASH_HashBuf(HASH_AlgSHA384, res, buf, len)
|
||||
== SECSuccess;
|
||||
#endif
|
||||
- case LDNS_HASH_GOST:
|
||||
+ case LDNS_HASH_GOST12:
|
||||
default:
|
||||
verbose(VERB_QUERY, "unknown DS digest algorithm %d",
|
||||
algo);
|
||||
@@ -1031,7 +1031,7 @@ dnskey_algo_id_is_supported(int id)
|
||||
case LDNS_ECDSAP384SHA384:
|
||||
return PK11_TokenExists(CKM_ECDSA);
|
||||
#endif
|
||||
- case LDNS_ECC_GOST:
|
||||
+ case LDNS_ECC_GOST12:
|
||||
default:
|
||||
return 0;
|
||||
}
|
||||
@@ -1352,7 +1352,7 @@ nss_setup_key_digest(int algo, SECKEYPublicKey** pubkey, HASH_HashType* htype,
|
||||
/* no prefix for DSA verification */
|
||||
break;
|
||||
#endif /* USE_ECDSA */
|
||||
- case LDNS_ECC_GOST:
|
||||
+ case LDNS_ECC_GOST12:
|
||||
default:
|
||||
verbose(VERB_QUERY, "verify: unknown algorithm %d",
|
||||
algo);
|
||||
@@ -1675,7 +1675,7 @@ ds_digest_size_supported(int algo)
|
||||
return SHA384_DIGEST_SIZE;
|
||||
#endif
|
||||
/* GOST not supported */
|
||||
- case LDNS_HASH_GOST:
|
||||
+ case LDNS_ECC_GOST12:
|
||||
default:
|
||||
break;
|
||||
}
|
||||
@@ -1700,7 +1700,7 @@ secalgo_ds_digest(int algo, unsigned char* buf, size_t len,
|
||||
return _digest_nettle(SHA384_DIGEST_SIZE, buf, len, res);
|
||||
|
||||
#endif
|
||||
- case LDNS_HASH_GOST:
|
||||
+ case LDNS_ECC_GOST12:
|
||||
default:
|
||||
verbose(VERB_QUERY, "unknown DS digest algorithm %d",
|
||||
algo);
|
||||
@@ -1744,7 +1744,7 @@ dnskey_algo_id_is_supported(int id)
|
||||
return 1;
|
||||
#endif
|
||||
case LDNS_RSAMD5: /* RFC 6725 deprecates RSAMD5 */
|
||||
- case LDNS_ECC_GOST:
|
||||
+ case LDNS_ECC_GOST12:
|
||||
default:
|
||||
return 0;
|
||||
}
|
||||
@@ -2103,7 +2103,7 @@ verify_canonrrset(sldns_buffer* buf, int algo, unsigned char* sigblock,
|
||||
return sec_status_secure;
|
||||
#endif
|
||||
case LDNS_RSAMD5:
|
||||
- case LDNS_ECC_GOST:
|
||||
+ case LDNS_ECC_GOST12:
|
||||
default:
|
||||
*reason = "unable to verify signature, unknown algorithm";
|
||||
return sec_status_bogus;
|
||||
+2
-2
@@ -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;
|
||||
}
|
||||
|
||||
+318
-20
@@ -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"
|
||||
@@ -199,6 +201,267 @@ signal_handling_playback(struct worker* wrk)
|
||||
sig_record_reload = 0;
|
||||
}
|
||||
|
||||
#ifdef HAVE_SSL
|
||||
/* setup a listening ssl context, fatal_exit() on any failure */
|
||||
static void
|
||||
setup_listen_sslctx(void** ctx, int is_dot, int is_doh,
|
||||
struct config_file* cfg, char* chroot)
|
||||
{
|
||||
char* key = cfg->ssl_service_key;
|
||||
char* pem = cfg->ssl_service_pem;
|
||||
if(chroot && strncmp(key, chroot, strlen(chroot)) == 0)
|
||||
key += strlen(chroot);
|
||||
if(chroot && pem && strncmp(pem, chroot, strlen(chroot)) == 0)
|
||||
pem += strlen(chroot);
|
||||
if(!(*ctx = listen_sslctx_create(key, pem, NULL,
|
||||
cfg->tls_ciphers, cfg->tls_ciphersuites,
|
||||
(cfg->tls_session_ticket_keys.first &&
|
||||
cfg->tls_session_ticket_keys.first->str[0] != 0),
|
||||
is_dot, is_doh, cfg->tls_protocols))) {
|
||||
log_err("could not set up listen SSL_CTX");
|
||||
*ctx = NULL;
|
||||
}
|
||||
}
|
||||
#endif /* HAVE_SSL */
|
||||
|
||||
#ifdef HAVE_SSL
|
||||
void* daemon_setup_listen_dot_sslctx(struct daemon* daemon,
|
||||
struct config_file* cfg)
|
||||
{
|
||||
void* ctx;
|
||||
(void)setup_listen_sslctx(&ctx, 1, 0, cfg, daemon->chroot);
|
||||
return ctx;
|
||||
}
|
||||
#endif /* HAVE_SSL */
|
||||
|
||||
#ifdef HAVE_SSL
|
||||
#ifdef HAVE_NGHTTP2_NGHTTP2_H
|
||||
void* daemon_setup_listen_doh_sslctx(struct daemon* daemon,
|
||||
struct config_file* cfg)
|
||||
{
|
||||
void* ctx;
|
||||
(void)setup_listen_sslctx(&ctx, 0, 1, cfg, daemon->chroot);
|
||||
return ctx;
|
||||
}
|
||||
#endif /* HAVE_NGHTTP2_NGHTTP2_H */
|
||||
#endif /* HAVE_SSL */
|
||||
|
||||
#ifdef HAVE_SSL
|
||||
#ifdef HAVE_NGTCP2
|
||||
void* daemon_setup_listen_quic_sslctx(struct daemon* daemon,
|
||||
struct config_file* cfg)
|
||||
{
|
||||
void* ctx;
|
||||
char* chroot = daemon->chroot;
|
||||
char* key = cfg->ssl_service_key;
|
||||
char* pem = cfg->ssl_service_pem;
|
||||
if(chroot && strncmp(key, chroot, strlen(chroot)) == 0)
|
||||
key += strlen(chroot);
|
||||
if(chroot && pem && strncmp(pem, chroot, strlen(chroot)) == 0)
|
||||
pem += strlen(chroot);
|
||||
|
||||
if(!(ctx = quic_sslctx_create(key, pem, NULL))) {
|
||||
log_err("could not set up quic SSL_CTX");
|
||||
return NULL;
|
||||
}
|
||||
return ctx;
|
||||
}
|
||||
#endif /* HAVE_NGTCP2 */
|
||||
#endif /* HAVE_SSL */
|
||||
|
||||
#ifdef HAVE_SSL
|
||||
void* daemon_setup_connect_dot_sslctx(struct daemon* daemon,
|
||||
struct config_file* cfg)
|
||||
{
|
||||
void* ctx;
|
||||
char* bundle, *chroot = daemon->chroot;
|
||||
bundle = cfg->tls_cert_bundle;
|
||||
if(chroot && bundle && strncmp(bundle, chroot, strlen(chroot)) == 0)
|
||||
bundle += strlen(chroot);
|
||||
|
||||
if(!(ctx = connect_sslctx_create(NULL, NULL, bundle,
|
||||
cfg->tls_win_cert))) {
|
||||
log_err("could not set up connect SSL_CTX");
|
||||
return NULL;
|
||||
}
|
||||
return ctx;
|
||||
}
|
||||
#endif /* HAVE_SSL */
|
||||
|
||||
/* setups the needed ssl contexts, fatal_exit() on any failure */
|
||||
void
|
||||
daemon_setup_sslctxs(struct daemon* daemon, struct config_file* cfg)
|
||||
{
|
||||
#ifdef HAVE_SSL
|
||||
char* chroot = daemon->chroot;
|
||||
if(cfg->ssl_service_key && cfg->ssl_service_key[0]) {
|
||||
char* key = cfg->ssl_service_key;
|
||||
char* pem = cfg->ssl_service_pem;
|
||||
if(chroot && strncmp(key, chroot, strlen(chroot)) == 0)
|
||||
key += strlen(chroot);
|
||||
if(chroot && pem && strncmp(pem, chroot, strlen(chroot)) == 0)
|
||||
pem += strlen(chroot);
|
||||
|
||||
/* setup the session keys; the callback to use them will be
|
||||
* attached to each sslctx separately */
|
||||
if(cfg->tls_session_ticket_keys.first &&
|
||||
cfg->tls_session_ticket_keys.first->str[0] != 0) {
|
||||
if(!listen_sslctx_setup_ticket_keys(
|
||||
cfg->tls_session_ticket_keys.first, chroot)) {
|
||||
fatal_exit("could not set session ticket SSL_CTX");
|
||||
}
|
||||
}
|
||||
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 */
|
||||
|
||||
/* Store the file name and mtime to detect changes later. */
|
||||
daemon->ssl_service_key = strdup(cfg->ssl_service_key);
|
||||
if(!daemon->ssl_service_key)
|
||||
fatal_exit("could not setup ssl ctx: out of memory");
|
||||
if(cfg->ssl_service_pem) {
|
||||
daemon->ssl_service_pem = strdup(cfg->ssl_service_pem);
|
||||
if(!daemon->ssl_service_pem)
|
||||
fatal_exit("could not setup ssl ctx: out of memory");
|
||||
} else {
|
||||
daemon->ssl_service_pem = NULL;
|
||||
}
|
||||
if(!file_get_mtime(key,
|
||||
&daemon->mtime_ssl_service_key,
|
||||
&daemon->mtime_ns_ssl_service_key, NULL))
|
||||
log_err("Could not stat(%s): %s",
|
||||
key, strerror(errno));
|
||||
if(pem) {
|
||||
if(!file_get_mtime(pem,
|
||||
&daemon->mtime_ssl_service_pem,
|
||||
&daemon->mtime_ns_ssl_service_pem, NULL))
|
||||
log_err("Could not stat(%s): %s",
|
||||
pem, strerror(errno));
|
||||
} else {
|
||||
daemon->mtime_ssl_service_pem = 0;
|
||||
daemon->mtime_ns_ssl_service_pem = 0;
|
||||
}
|
||||
}
|
||||
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 */
|
||||
}
|
||||
|
||||
/** Delete the ssl ctxs */
|
||||
static void
|
||||
daemon_delete_sslctxs(struct daemon* daemon)
|
||||
{
|
||||
#ifdef HAVE_SSL
|
||||
listen_sslctx_delete_ticket_keys();
|
||||
SSL_CTX_free((SSL_CTX*)daemon->listen_dot_sslctx);
|
||||
daemon->listen_dot_sslctx = NULL;
|
||||
SSL_CTX_free((SSL_CTX*)daemon->listen_doh_sslctx);
|
||||
daemon->listen_doh_sslctx = NULL;
|
||||
SSL_CTX_free((SSL_CTX*)daemon->connect_dot_sslctx);
|
||||
daemon->connect_dot_sslctx = NULL;
|
||||
free(daemon->ssl_service_key);
|
||||
daemon->ssl_service_key = NULL;
|
||||
free(daemon->ssl_service_pem);
|
||||
daemon->ssl_service_pem = NULL;
|
||||
#else
|
||||
(void)daemon;
|
||||
#endif
|
||||
#ifdef HAVE_NGTCP2
|
||||
SSL_CTX_free((SSL_CTX*)daemon->listen_quic_sslctx);
|
||||
daemon->listen_quic_sslctx = NULL;
|
||||
#endif
|
||||
}
|
||||
|
||||
int
|
||||
ssl_cert_changed(struct daemon* daemon, struct config_file* cfg)
|
||||
{
|
||||
time_t mtime = 0;
|
||||
long ns = 0;
|
||||
char* chroot = daemon->chroot;
|
||||
char* key = cfg->ssl_service_key;
|
||||
char* pem = cfg->ssl_service_pem;
|
||||
log_assert(daemon->ssl_service_key && cfg->ssl_service_key);
|
||||
if(chroot && strncmp(key, chroot, strlen(chroot)) == 0)
|
||||
key += strlen(chroot);
|
||||
if(chroot && pem && strncmp(pem, chroot, strlen(chroot)) == 0)
|
||||
pem += strlen(chroot);
|
||||
|
||||
if(strcmp(daemon->ssl_service_key, cfg->ssl_service_key) != 0)
|
||||
return 1;
|
||||
if(daemon->ssl_service_pem && cfg->ssl_service_pem &&
|
||||
strcmp(daemon->ssl_service_pem, cfg->ssl_service_pem) != 0)
|
||||
return 1;
|
||||
if(!file_get_mtime(key, &mtime, &ns, NULL)) {
|
||||
log_err("Could not stat(%s): %s",
|
||||
key, strerror(errno));
|
||||
/* It has probably changed, but file read is likely going to
|
||||
* fail. */
|
||||
return 0;
|
||||
}
|
||||
if(mtime != daemon->mtime_ssl_service_key ||
|
||||
ns != daemon->mtime_ns_ssl_service_key)
|
||||
return 1;
|
||||
if(pem) {
|
||||
if(!file_get_mtime(pem, &mtime, &ns, NULL)) {
|
||||
log_err("Could not stat(%s): %s",
|
||||
pem, strerror(errno));
|
||||
/* It has probably changed, but file read is likely going to
|
||||
* fail. */
|
||||
return 0;
|
||||
}
|
||||
if(mtime != daemon->mtime_ssl_service_pem ||
|
||||
ns != daemon->mtime_ns_ssl_service_pem)
|
||||
return 1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
/** Reload the sslctxs if they have changed */
|
||||
static void
|
||||
daemon_reload_sslctxs(struct daemon* daemon)
|
||||
{
|
||||
#ifdef HAVE_SSL
|
||||
if(daemon->cfg->ssl_service_key && daemon->cfg->ssl_service_key[0]) {
|
||||
/* See if changed */
|
||||
if(!daemon->ssl_service_key ||
|
||||
ssl_cert_changed(daemon,daemon->cfg)) {
|
||||
verbose(VERB_ALGO, "Reloading certificates");
|
||||
daemon_delete_sslctxs(daemon);
|
||||
daemon_setup_sslctxs(daemon, daemon->cfg);
|
||||
}
|
||||
} else {
|
||||
/* See if sslctxs are removed from config. */
|
||||
if(daemon->ssl_service_key) {
|
||||
verbose(VERB_ALGO, "Removing certificates");
|
||||
daemon_delete_sslctxs(daemon);
|
||||
}
|
||||
}
|
||||
#else
|
||||
(void)daemon;
|
||||
#endif
|
||||
}
|
||||
|
||||
struct daemon*
|
||||
daemon_init(void)
|
||||
{
|
||||
@@ -235,7 +498,11 @@ daemon_init(void)
|
||||
# else
|
||||
OPENSSL_init_crypto(OPENSSL_INIT_ADD_ALL_CIPHERS
|
||||
| OPENSSL_INIT_ADD_ALL_DIGESTS
|
||||
| OPENSSL_INIT_LOAD_CRYPTO_STRINGS, NULL);
|
||||
| OPENSSL_INIT_LOAD_CRYPTO_STRINGS
|
||||
# if defined(OPENSSL_INIT_NO_LOAD_CONFIG) && defined(UB_ON_WINDOWS)
|
||||
| OPENSSL_INIT_NO_LOAD_CONFIG
|
||||
# endif
|
||||
, NULL);
|
||||
# endif
|
||||
# if HAVE_DECL_SSL_COMP_GET_COMPRESSION_METHODS
|
||||
/* grab the COMP method ptr because openssl leaks it */
|
||||
@@ -244,7 +511,11 @@ daemon_init(void)
|
||||
# if OPENSSL_VERSION_NUMBER < 0x10100000 || !defined(HAVE_OPENSSL_INIT_SSL)
|
||||
(void)SSL_library_init();
|
||||
# else
|
||||
(void)OPENSSL_init_ssl(OPENSSL_INIT_LOAD_SSL_STRINGS, NULL);
|
||||
(void)OPENSSL_init_ssl(OPENSSL_INIT_LOAD_SSL_STRINGS
|
||||
# if defined(OPENSSL_INIT_NO_LOAD_CONFIG) && defined(UB_ON_WINDOWS)
|
||||
| OPENSSL_INIT_NO_LOAD_CONFIG
|
||||
# endif
|
||||
, NULL);
|
||||
# endif
|
||||
# if defined(HAVE_SSL) && defined(OPENSSL_THREADS) && !defined(THREADS_DISABLED)
|
||||
if(!ub_openssl_lock_init())
|
||||
@@ -320,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;
|
||||
}
|
||||
|
||||
@@ -556,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)) {
|
||||
@@ -586,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. */
|
||||
@@ -663,6 +946,14 @@ thread_start(void* arg)
|
||||
struct worker* worker = (struct worker*)arg;
|
||||
int port_num = 0;
|
||||
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);
|
||||
/* 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
|
||||
/* close pipe ends used by main */
|
||||
@@ -676,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;
|
||||
@@ -737,6 +1029,7 @@ daemon_fork(struct daemon* daemon)
|
||||
#endif
|
||||
|
||||
log_assert(daemon);
|
||||
daemon_reload_sslctxs(daemon);
|
||||
if(!(daemon->env->views = views_create()))
|
||||
fatal_exit("Could not create views: out of memory");
|
||||
/* create individual views and their localzone/data trees */
|
||||
@@ -829,11 +1122,18 @@ daemon_fork(struct daemon* daemon)
|
||||
* the thread_start() procedure.
|
||||
*/
|
||||
set_log_thread_id(daemon->workers[0], daemon->cfg);
|
||||
/* If shm stats need an offset, calculate it */
|
||||
if(daemon->cfg->shm_enable && daemon->cfg->stat_interval > 0) {
|
||||
daemon->stat_time_specific = 1;
|
||||
daemon->stat_time_offset =
|
||||
((int)time(NULL))%daemon->cfg->stat_interval;
|
||||
}
|
||||
|
||||
#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.
|
||||
@@ -846,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]);
|
||||
|
||||
@@ -891,7 +1192,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
|
||||
@@ -933,6 +1233,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;
|
||||
@@ -972,6 +1274,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);
|
||||
@@ -983,15 +1286,7 @@ daemon_delete(struct daemon* daemon)
|
||||
free(daemon->pidfile);
|
||||
free(daemon->cfgfile);
|
||||
free(daemon->env);
|
||||
#ifdef HAVE_SSL
|
||||
listen_sslctx_delete_ticket_keys();
|
||||
SSL_CTX_free((SSL_CTX*)daemon->listen_dot_sslctx);
|
||||
SSL_CTX_free((SSL_CTX*)daemon->listen_doh_sslctx);
|
||||
SSL_CTX_free((SSL_CTX*)daemon->connect_dot_sslctx);
|
||||
#endif
|
||||
#ifdef HAVE_NGTCP2
|
||||
SSL_CTX_free((SSL_CTX*)daemon->listen_quic_sslctx);
|
||||
#endif
|
||||
daemon_delete_sslctxs(daemon);
|
||||
free(daemon);
|
||||
/* lex cleanup */
|
||||
ub_c_lex_destroy();
|
||||
@@ -1003,7 +1298,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
|
||||
@@ -1026,6 +1321,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 */
|
||||
@@ -107,6 +111,18 @@ struct daemon {
|
||||
void* listen_doh_sslctx;
|
||||
/** ssl context for listening to quic */
|
||||
void* listen_quic_sslctx;
|
||||
/** the file name that the ssl context is made with, private key. */
|
||||
char* ssl_service_key;
|
||||
/** the file name that the ssl context is made with, certificate. */
|
||||
char* ssl_service_pem;
|
||||
/** modification time for ssl_service_key, in sec and ns. Like
|
||||
* in a struct timespec, but without that for portability. */
|
||||
time_t mtime_ssl_service_key;
|
||||
long mtime_ns_ssl_service_key;
|
||||
/** modification time for ssl_service_pem, in sec and ns. Like
|
||||
* in a struct timespec, but without that for portability. */
|
||||
time_t mtime_ssl_service_pem;
|
||||
long mtime_ns_ssl_service_pem;
|
||||
/** num threads allocated */
|
||||
int num;
|
||||
/** num threads allocated in the previous config or 0 at first */
|
||||
@@ -143,7 +159,14 @@ struct daemon {
|
||||
/** the dnstap environment master value, copied and changed by threads*/
|
||||
struct dt_env* dtenv;
|
||||
#endif
|
||||
/** The SHM info for shared memory stats. */
|
||||
struct shm_main_info* shm_info;
|
||||
/** if the timeout for statistics is attempted at specific offset.
|
||||
* If it is true, the stat timeout is the interval+offset, and that
|
||||
* picks (roughly) the same time offset every time period. */
|
||||
int stat_time_specific;
|
||||
/** if the timeout is specific, what offset in the period. */
|
||||
int stat_time_offset;
|
||||
/** some response-ip tags or actions are configured if true */
|
||||
int use_response_ip;
|
||||
/** some RPZ policies are configured */
|
||||
@@ -169,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;
|
||||
};
|
||||
|
||||
/**
|
||||
@@ -229,4 +254,26 @@ void daemon_apply_cfg(struct daemon* daemon, struct config_file* cfg);
|
||||
*/
|
||||
int setup_acl_for_ports(struct acl_list* list, struct listen_port* port_list);
|
||||
|
||||
/* setups the needed ssl contexts, fatal_exit() on any failure */
|
||||
void daemon_setup_sslctxs(struct daemon* daemon, struct config_file* cfg);
|
||||
|
||||
/** See if the SSL cert files have changed */
|
||||
int ssl_cert_changed(struct daemon* daemon, struct config_file* cfg);
|
||||
|
||||
/** Setup the listening DoT SSL_CTX, returns the ssl ctx. */
|
||||
void* daemon_setup_listen_dot_sslctx(struct daemon* daemon,
|
||||
struct config_file* cfg);
|
||||
|
||||
/** Setup the listening DoH SSL_CTX, returns the ssl ctx. */
|
||||
void* daemon_setup_listen_doh_sslctx(struct daemon* daemon,
|
||||
struct config_file* cfg);
|
||||
|
||||
/** Setup the listening Quic SSL_CTX, returns the ssl ctx */
|
||||
void* daemon_setup_listen_quic_sslctx(struct daemon* daemon,
|
||||
struct config_file* cfg);
|
||||
|
||||
/** Setup the connect DoT SSL_CTX, returns the ssl ctx */
|
||||
void* daemon_setup_connect_dot_sslctx(struct daemon* daemon,
|
||||
struct config_file* cfg);
|
||||
|
||||
#endif /* DAEMON_H */
|
||||
|
||||
+539
-389
File diff suppressed because it is too large
Load Diff
+3
-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;
|
||||
@@ -255,6 +256,8 @@ struct fast_reload_thread {
|
||||
struct fast_reload_auth_change* auth_zone_change_list;
|
||||
/** the old tree of auth zones, to lookup. */
|
||||
struct auth_zones* old_auth_zones;
|
||||
/** If the ssl ctxs have changed. */
|
||||
int sslctxs_changed;
|
||||
};
|
||||
|
||||
/**
|
||||
@@ -363,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)
|
||||
|
||||
+4
-47
@@ -463,57 +463,13 @@ detach(void)
|
||||
#endif /* HAVE_DAEMON */
|
||||
}
|
||||
|
||||
#ifdef HAVE_SSL
|
||||
/* setup a listening ssl context, fatal_exit() on any failure */
|
||||
/** setup the remote and ticket keys */
|
||||
static void
|
||||
setup_listen_sslctx(void** ctx, int is_dot, int is_doh, struct config_file* cfg)
|
||||
{
|
||||
if(!(*ctx = listen_sslctx_create(
|
||||
cfg->ssl_service_key, cfg->ssl_service_pem, NULL,
|
||||
cfg->tls_ciphers, cfg->tls_ciphersuites,
|
||||
(cfg->tls_session_ticket_keys.first &&
|
||||
cfg->tls_session_ticket_keys.first->str[0] != 0),
|
||||
is_dot, is_doh, cfg->tls_use_system_policy_versions))) {
|
||||
fatal_exit("could not set up listen SSL_CTX");
|
||||
}
|
||||
}
|
||||
#endif /* HAVE_SSL */
|
||||
|
||||
/* setups the needed ssl contexts, fatal_exit() on any failure */
|
||||
static void
|
||||
setup_sslctxs(struct daemon* daemon, struct config_file* cfg)
|
||||
setup_sslctx_remote(struct daemon* daemon, struct config_file* cfg)
|
||||
{
|
||||
#ifdef HAVE_SSL
|
||||
if(!(daemon->rc = daemon_remote_create(cfg)))
|
||||
fatal_exit("could not set up remote-control");
|
||||
if(cfg->ssl_service_key && cfg->ssl_service_key[0]) {
|
||||
/* setup the session keys; the callback to use them will be
|
||||
* attached to each sslctx separately */
|
||||
if(cfg->tls_session_ticket_keys.first &&
|
||||
cfg->tls_session_ticket_keys.first->str[0] != 0) {
|
||||
if(!listen_sslctx_setup_ticket_keys(
|
||||
cfg->tls_session_ticket_keys.first)) {
|
||||
fatal_exit("could not set session ticket SSL_CTX");
|
||||
}
|
||||
}
|
||||
(void)setup_listen_sslctx(&daemon->listen_dot_sslctx, 1, 0, cfg);
|
||||
#ifdef HAVE_NGHTTP2_NGHTTP2_H
|
||||
if(cfg_has_https(cfg)) {
|
||||
(void)setup_listen_sslctx(&daemon->listen_doh_sslctx, 0, 1, cfg);
|
||||
}
|
||||
#endif
|
||||
#ifdef HAVE_NGTCP2
|
||||
if(cfg_has_quic(cfg)) {
|
||||
if(!(daemon->listen_quic_sslctx = quic_sslctx_create(
|
||||
cfg->ssl_service_key, cfg->ssl_service_pem, NULL))) {
|
||||
fatal_exit("could not set up quic SSL_CTX");
|
||||
}
|
||||
}
|
||||
#endif /* HAVE_NGTCP2 */
|
||||
}
|
||||
if(!(daemon->connect_dot_sslctx = connect_sslctx_create(NULL, NULL,
|
||||
cfg->tls_cert_bundle, cfg->tls_win_cert)))
|
||||
fatal_exit("could not set up connect SSL_CTX");
|
||||
#else /* HAVE_SSL */
|
||||
(void)daemon;(void)cfg;
|
||||
#endif /* HAVE_SSL */
|
||||
@@ -545,7 +501,8 @@ perform_setup(struct daemon* daemon, struct config_file* cfg, int debug_mode,
|
||||
#endif
|
||||
|
||||
/* read ssl keys while superuser and outside chroot */
|
||||
(void)setup_sslctxs(daemon, cfg);
|
||||
setup_sslctx_remote(daemon, cfg);
|
||||
daemon_setup_sslctxs(daemon, cfg);
|
||||
|
||||
/* init syslog (as root) if needed, before daemonize, otherwise
|
||||
* a fork error could not be printed since daemonize closed stderr.*/
|
||||
|
||||
+190
-108
@@ -255,7 +255,8 @@ worker_handle_service_reply(struct comm_point* c, void* arg, int error,
|
||||
return 0;
|
||||
}
|
||||
/* sanity check. */
|
||||
if(!LDNS_QR_WIRE(sldns_buffer_begin(c->buffer))
|
||||
if(sldns_buffer_limit(c->buffer) < LDNS_HEADER_SIZE
|
||||
|| !LDNS_QR_WIRE(sldns_buffer_begin(c->buffer))
|
||||
|| LDNS_OPCODE_WIRE(sldns_buffer_begin(c->buffer)) !=
|
||||
LDNS_PACKET_QUERY
|
||||
|| LDNS_QDCOUNT(sldns_buffer_begin(c->buffer)) > 1) {
|
||||
@@ -292,6 +293,44 @@ worker_err_ratelimit(struct worker* worker, int err)
|
||||
return err;
|
||||
}
|
||||
|
||||
/**
|
||||
* Reply with an error.
|
||||
* This reply includes the qname if it has been parsed.
|
||||
* For error ratelimiting, the err ratelimit routine should be checked
|
||||
* beforehand. The reply is without EDNS, and copies RD and sets QR flag.
|
||||
* @param pkt: the packet buffer from the comm point.
|
||||
* @param err: the error code that would be wanted.
|
||||
* @param qname_len: 0 if not parsed, and the qname length in packet.
|
||||
*/
|
||||
static void
|
||||
query_error(sldns_buffer* pkt, int err, size_t qname_len)
|
||||
{
|
||||
/* Preserve the RD flag.
|
||||
* The CD flag must be cleared in authoritative answers,
|
||||
* also the AD flag need not be copied into answers.
|
||||
* The other flags need not be copied into the answer. */
|
||||
sldns_buffer_write_u16_at(pkt, 2,
|
||||
sldns_buffer_read_u16_at(pkt, 2)&0x0100U);
|
||||
LDNS_QR_SET(sldns_buffer_begin(pkt)); /* Set QR flag. */
|
||||
LDNS_RCODE_SET(sldns_buffer_begin(pkt), err); /* Set rcode */
|
||||
|
||||
if(qname_len && LDNS_QDCOUNT(sldns_buffer_begin(pkt))>=1 &&
|
||||
qname_len <= LDNS_MAX_DOMAINLEN) {
|
||||
/* Copy query into the answer. */
|
||||
LDNS_QDCOUNT_SET(sldns_buffer_begin(pkt), 1);
|
||||
sldns_buffer_set_position(pkt, LDNS_HEADER_SIZE +
|
||||
qname_len + 2 /* type */ + 2 /* class */ );
|
||||
} else {
|
||||
/* No query section in answer. */
|
||||
LDNS_QDCOUNT_SET(sldns_buffer_begin(pkt), 0);
|
||||
sldns_buffer_set_position(pkt, LDNS_HEADER_SIZE);
|
||||
}
|
||||
LDNS_ANCOUNT_SET(sldns_buffer_begin(pkt), 0);
|
||||
LDNS_NSCOUNT_SET(sldns_buffer_begin(pkt), 0);
|
||||
LDNS_ARCOUNT_SET(sldns_buffer_begin(pkt), 0);
|
||||
sldns_buffer_flip(pkt);
|
||||
}
|
||||
|
||||
/**
|
||||
* Structure holding the result of the worker_check_request function.
|
||||
* Based on configuration it could be called up to four times; ideally should
|
||||
@@ -329,7 +368,6 @@ worker_check_request(sldns_buffer* pkt, struct worker* worker,
|
||||
return;
|
||||
}
|
||||
if(LDNS_TC_WIRE(sldns_buffer_begin(pkt))) {
|
||||
LDNS_TC_CLR(sldns_buffer_begin(pkt));
|
||||
verbose(VERB_QUERY, "request bad, has TC bit on");
|
||||
out->value = worker_err_ratelimit(worker, LDNS_RCODE_FORMERR);
|
||||
return;
|
||||
@@ -463,7 +501,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);
|
||||
@@ -676,7 +716,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;
|
||||
@@ -687,7 +728,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;
|
||||
|
||||
@@ -734,7 +775,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;
|
||||
@@ -844,7 +885,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,
|
||||
@@ -971,6 +1012,7 @@ chaos_replystr(sldns_buffer* pkt, char** str, int num, struct edns_data* edns,
|
||||
size_t udpsize = edns->udp_size;
|
||||
edns->edns_version = EDNS_ADVERTISED_VERSION;
|
||||
edns->udp_size = EDNS_ADVERTISED_SIZE;
|
||||
edns->ext_rcode = 0;
|
||||
edns->bits &= EDNS_DO;
|
||||
if(!inplace_cb_reply_local_call(&worker->env, NULL, NULL, NULL,
|
||||
LDNS_RCODE_NOERROR, edns, repinfo, worker->scratchpad,
|
||||
@@ -1229,9 +1271,7 @@ deny_refuse(struct comm_point* c, enum acl_access acl,
|
||||
worker_check_request(c->buffer, worker, check_result);
|
||||
if(check_result->value != 0) {
|
||||
if(check_result->value != -1) {
|
||||
LDNS_QR_SET(sldns_buffer_begin(c->buffer));
|
||||
LDNS_RCODE_SET(sldns_buffer_begin(c->buffer),
|
||||
check_result->value);
|
||||
query_error(c->buffer, check_result->value, 0);
|
||||
return 1;
|
||||
}
|
||||
comm_point_drop_reply(repinfo);
|
||||
@@ -1248,41 +1288,17 @@ deny_refuse(struct comm_point* c, enum acl_access acl,
|
||||
/* check additional section is present and that we respond with EDEs */
|
||||
if(LDNS_ARCOUNT(sldns_buffer_begin(c->buffer)) != 1
|
||||
|| !ede) {
|
||||
LDNS_QDCOUNT_SET(sldns_buffer_begin(c->buffer), 0);
|
||||
LDNS_ANCOUNT_SET(sldns_buffer_begin(c->buffer), 0);
|
||||
LDNS_NSCOUNT_SET(sldns_buffer_begin(c->buffer), 0);
|
||||
LDNS_ARCOUNT_SET(sldns_buffer_begin(c->buffer), 0);
|
||||
LDNS_QR_SET(sldns_buffer_begin(c->buffer));
|
||||
LDNS_RCODE_SET(sldns_buffer_begin(c->buffer),
|
||||
LDNS_RCODE_REFUSED);
|
||||
sldns_buffer_set_position(c->buffer, LDNS_HEADER_SIZE);
|
||||
sldns_buffer_flip(c->buffer);
|
||||
query_error(c->buffer, LDNS_RCODE_REFUSED, 0);
|
||||
return 1;
|
||||
}
|
||||
|
||||
if (!query_dname_len(c->buffer)) {
|
||||
LDNS_QDCOUNT_SET(sldns_buffer_begin(c->buffer), 0);
|
||||
LDNS_ANCOUNT_SET(sldns_buffer_begin(c->buffer), 0);
|
||||
LDNS_NSCOUNT_SET(sldns_buffer_begin(c->buffer), 0);
|
||||
LDNS_ARCOUNT_SET(sldns_buffer_begin(c->buffer), 0);
|
||||
LDNS_QR_SET(sldns_buffer_begin(c->buffer));
|
||||
LDNS_RCODE_SET(sldns_buffer_begin(c->buffer),
|
||||
LDNS_RCODE_FORMERR);
|
||||
sldns_buffer_set_position(c->buffer, LDNS_HEADER_SIZE);
|
||||
sldns_buffer_flip(c->buffer);
|
||||
query_error(c->buffer, LDNS_RCODE_FORMERR, 0);
|
||||
return 1;
|
||||
}
|
||||
/* space available for query type and class? */
|
||||
if (sldns_buffer_remaining(c->buffer) < 2 * sizeof(uint16_t)) {
|
||||
LDNS_QR_SET(sldns_buffer_begin(c->buffer));
|
||||
LDNS_RCODE_SET(sldns_buffer_begin(c->buffer),
|
||||
LDNS_RCODE_FORMERR);
|
||||
LDNS_QDCOUNT_SET(sldns_buffer_begin(c->buffer), 0);
|
||||
LDNS_ANCOUNT_SET(sldns_buffer_begin(c->buffer), 0);
|
||||
LDNS_NSCOUNT_SET(sldns_buffer_begin(c->buffer), 0);
|
||||
LDNS_ARCOUNT_SET(sldns_buffer_begin(c->buffer), 0);
|
||||
sldns_buffer_set_position(c->buffer, LDNS_HEADER_SIZE);
|
||||
sldns_buffer_flip(c->buffer);
|
||||
query_error(c->buffer, LDNS_RCODE_FORMERR, 0);
|
||||
return 1;
|
||||
}
|
||||
LDNS_QR_SET(sldns_buffer_begin(c->buffer));
|
||||
@@ -1304,35 +1320,27 @@ deny_refuse(struct comm_point* c, enum acl_access acl,
|
||||
if(!skip_pkt_rrs(c->buffer,
|
||||
((int)LDNS_ANCOUNT(sldns_buffer_begin(c->buffer)))+
|
||||
((int)LDNS_NSCOUNT(sldns_buffer_begin(c->buffer))))) {
|
||||
LDNS_RCODE_SET(sldns_buffer_begin(c->buffer),
|
||||
LDNS_RCODE_FORMERR);
|
||||
LDNS_ANCOUNT_SET(sldns_buffer_begin(c->buffer), 0);
|
||||
LDNS_NSCOUNT_SET(sldns_buffer_begin(c->buffer), 0);
|
||||
LDNS_ARCOUNT_SET(sldns_buffer_begin(c->buffer), 0);
|
||||
sldns_buffer_set_position(c->buffer, opt_rr_mark);
|
||||
sldns_buffer_flip(c->buffer);
|
||||
query_error(c->buffer, LDNS_RCODE_FORMERR,
|
||||
opt_rr_mark - LDNS_HEADER_SIZE
|
||||
- 2 /* qtype */ - 2 /* qclass */);
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
/* Do we have a valid OPT RR here? If not return REFUSED (could be a valid TSIG or something so no FORMERR) */
|
||||
/* domain name must be the root of length 1. */
|
||||
if(sldns_buffer_remaining(c->buffer) < 1 || *sldns_buffer_current(c->buffer) != 0) {
|
||||
LDNS_ANCOUNT_SET(sldns_buffer_begin(c->buffer), 0);
|
||||
LDNS_NSCOUNT_SET(sldns_buffer_begin(c->buffer), 0);
|
||||
LDNS_ARCOUNT_SET(sldns_buffer_begin(c->buffer), 0);
|
||||
sldns_buffer_set_position(c->buffer, opt_rr_mark);
|
||||
sldns_buffer_flip(c->buffer);
|
||||
query_error(c->buffer, LDNS_RCODE_REFUSED,
|
||||
opt_rr_mark - LDNS_HEADER_SIZE
|
||||
- 2 /* qtype */ - 2 /* qclass */);
|
||||
return 1;
|
||||
} else {
|
||||
sldns_buffer_skip(c->buffer, 1); /* skip root label */
|
||||
}
|
||||
if(sldns_buffer_remaining(c->buffer) < 2 ||
|
||||
sldns_buffer_read_u16(c->buffer) != LDNS_RR_TYPE_OPT) {
|
||||
LDNS_ANCOUNT_SET(sldns_buffer_begin(c->buffer), 0);
|
||||
LDNS_NSCOUNT_SET(sldns_buffer_begin(c->buffer), 0);
|
||||
LDNS_ARCOUNT_SET(sldns_buffer_begin(c->buffer), 0);
|
||||
sldns_buffer_set_position(c->buffer, opt_rr_mark);
|
||||
sldns_buffer_flip(c->buffer);
|
||||
query_error(c->buffer, LDNS_RCODE_REFUSED,
|
||||
opt_rr_mark - LDNS_HEADER_SIZE
|
||||
- 2 /* qtype */ - 2 /* qclass */);
|
||||
return 1;
|
||||
}
|
||||
/* Write OPT RR directly after the query,
|
||||
@@ -1489,6 +1497,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};
|
||||
@@ -1506,7 +1516,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;
|
||||
@@ -1528,6 +1538,10 @@ worker_handle_request(struct comm_point* c, void* arg, int error,
|
||||
"dnscrypt: worker check request: bad query.");
|
||||
log_addr(VERB_CLIENT,"from",&repinfo->client_addr,
|
||||
repinfo->client_addrlen);
|
||||
if(check_result.value != -1) {
|
||||
query_error(c->buffer, check_result.value, 0);
|
||||
return 1;
|
||||
}
|
||||
comm_point_drop_reply(repinfo);
|
||||
return 0;
|
||||
}
|
||||
@@ -1536,8 +1550,13 @@ worker_handle_request(struct comm_point* c, void* arg, int error,
|
||||
"dnscrypt: worker parse request: formerror.");
|
||||
log_addr(VERB_CLIENT, "from", &repinfo->client_addr,
|
||||
repinfo->client_addrlen);
|
||||
comm_point_drop_reply(repinfo);
|
||||
return 0;
|
||||
if(worker_err_ratelimit(worker, LDNS_RCODE_FORMERR) == -1) {
|
||||
comm_point_drop_reply(repinfo);
|
||||
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);
|
||||
if(!(qinfo.qtype == LDNS_RR_TYPE_TXT &&
|
||||
@@ -1548,9 +1567,15 @@ worker_handle_request(struct comm_point* c, void* arg, int error,
|
||||
worker->daemon->dnscenv->provider_name,
|
||||
sldns_rr_descript(qinfo.qtype)->_name,
|
||||
buf);
|
||||
comm_point_drop_reply(repinfo);
|
||||
if(worker_err_ratelimit(worker, LDNS_RCODE_SERVFAIL) == -1) {
|
||||
comm_point_drop_reply(repinfo);
|
||||
return 0;
|
||||
}
|
||||
query_error(c->buffer, LDNS_RCODE_SERVFAIL,
|
||||
qinfo.qname_len);
|
||||
worker->stats.num_query_dnscrypt_cleartext++;
|
||||
return 0;
|
||||
sldns_buffer_copy(c->dnscrypt_buffer, c->buffer);
|
||||
return 1;
|
||||
}
|
||||
worker->stats.num_query_dnscrypt_cert++;
|
||||
sldns_buffer_rewind(c->buffer);
|
||||
@@ -1590,9 +1615,7 @@ worker_handle_request(struct comm_point* c, void* arg, int error,
|
||||
verbose(VERB_ALGO, "worker check request: bad query.");
|
||||
log_addr(VERB_CLIENT,"from",&repinfo->client_addr, repinfo->client_addrlen);
|
||||
if(check_result.value != -1) {
|
||||
LDNS_QR_SET(sldns_buffer_begin(c->buffer));
|
||||
LDNS_RCODE_SET(sldns_buffer_begin(c->buffer),
|
||||
check_result.value);
|
||||
query_error(c->buffer, check_result.value, 0);
|
||||
return 1;
|
||||
}
|
||||
comm_point_drop_reply(repinfo);
|
||||
@@ -1626,10 +1649,7 @@ worker_handle_request(struct comm_point* c, void* arg, int error,
|
||||
comm_point_drop_reply(repinfo);
|
||||
return 0;
|
||||
}
|
||||
sldns_buffer_rewind(c->buffer);
|
||||
LDNS_QR_SET(sldns_buffer_begin(c->buffer));
|
||||
LDNS_RCODE_SET(sldns_buffer_begin(c->buffer),
|
||||
LDNS_RCODE_FORMERR);
|
||||
query_error(c->buffer, LDNS_RCODE_FORMERR, 0);
|
||||
goto send_reply;
|
||||
}
|
||||
if(worker->env.cfg->log_queries) {
|
||||
@@ -1642,10 +1662,11 @@ worker_handle_request(struct comm_point* c, void* arg, int error,
|
||||
verbose(VERB_ALGO, "worker request: refused zone transfer.");
|
||||
log_addr(VERB_CLIENT, "from", &repinfo->client_addr,
|
||||
repinfo->client_addrlen);
|
||||
sldns_buffer_rewind(c->buffer);
|
||||
LDNS_QR_SET(sldns_buffer_begin(c->buffer));
|
||||
LDNS_RCODE_SET(sldns_buffer_begin(c->buffer),
|
||||
LDNS_RCODE_REFUSED);
|
||||
if(worker_err_ratelimit(worker, LDNS_RCODE_REFUSED) == -1) {
|
||||
comm_point_drop_reply(repinfo);
|
||||
return 0;
|
||||
}
|
||||
query_error(c->buffer, LDNS_RCODE_REFUSED, qinfo.qname_len);
|
||||
if(worker->stats.extended) {
|
||||
worker->stats.qtype[qinfo.qtype]++;
|
||||
}
|
||||
@@ -1664,10 +1685,7 @@ worker_handle_request(struct comm_point* c, void* arg, int error,
|
||||
comm_point_drop_reply(repinfo);
|
||||
return 0;
|
||||
}
|
||||
sldns_buffer_rewind(c->buffer);
|
||||
LDNS_QR_SET(sldns_buffer_begin(c->buffer));
|
||||
LDNS_RCODE_SET(sldns_buffer_begin(c->buffer),
|
||||
LDNS_RCODE_FORMERR);
|
||||
query_error(c->buffer, LDNS_RCODE_FORMERR, qinfo.qname_len);
|
||||
if(worker->stats.extended) {
|
||||
worker->stats.qtype[qinfo.qtype]++;
|
||||
}
|
||||
@@ -1675,13 +1693,17 @@ worker_handle_request(struct comm_point* c, void* arg, int error,
|
||||
}
|
||||
if((ret=parse_edns_from_query_pkt(
|
||||
c->buffer, &edns, worker->env.cfg, c, repinfo,
|
||||
(worker->env.now ? *worker->env.now : time(NULL)),
|
||||
worker->scratchpad,
|
||||
*worker->env.now, worker->scratchpad,
|
||||
worker->daemon->cookie_secrets)) != 0) {
|
||||
struct edns_data reply_edns;
|
||||
verbose(VERB_ALGO, "worker parse edns: formerror.");
|
||||
log_addr(VERB_CLIENT, "from", &repinfo->client_addr,
|
||||
repinfo->client_addrlen);
|
||||
if(worker_err_ratelimit(worker, ret) == -1) {
|
||||
comm_point_drop_reply(repinfo);
|
||||
regional_free_all(worker->scratchpad);
|
||||
return 0;
|
||||
}
|
||||
memset(&reply_edns, 0, sizeof(reply_edns));
|
||||
reply_edns.edns_present = 1;
|
||||
error_encode(c->buffer, ret, &qinfo,
|
||||
@@ -1698,6 +1720,11 @@ worker_handle_request(struct comm_point* c, void* arg, int error,
|
||||
verbose(VERB_ALGO, "query with bad edns version.");
|
||||
log_addr(VERB_CLIENT, "from", &repinfo->client_addr,
|
||||
repinfo->client_addrlen);
|
||||
if(worker_err_ratelimit(worker, EDNS_RCODE_BADVERS) == -1) {
|
||||
comm_point_drop_reply(repinfo);
|
||||
regional_free_all(worker->scratchpad);
|
||||
return 0;
|
||||
}
|
||||
extended_error_encode(c->buffer, EDNS_RCODE_BADVERS, &qinfo,
|
||||
*(uint16_t*)(void *)sldns_buffer_begin(c->buffer),
|
||||
sldns_buffer_read_u16_at(c->buffer, 2), 0, &edns);
|
||||
@@ -1743,6 +1770,11 @@ worker_handle_request(struct comm_point* c, void* arg, int error,
|
||||
|
||||
else if(edns.cookie_present) {
|
||||
/* Cookie present, but not valid: Cookie was bad! */
|
||||
if(worker_err_ratelimit(worker, LDNS_EXT_RCODE_BADCOOKIE) == -1) {
|
||||
comm_point_drop_reply(repinfo);
|
||||
regional_free_all(worker->scratchpad);
|
||||
return 0;
|
||||
}
|
||||
extended_error_encode(c->buffer,
|
||||
LDNS_EXT_RCODE_BADCOOKIE, &qinfo,
|
||||
*(uint16_t*)(void *)
|
||||
@@ -1757,6 +1789,11 @@ worker_handle_request(struct comm_point* c, void* arg, int error,
|
||||
"need cookie or stateful transport");
|
||||
log_addr(VERB_ALGO, "from",&repinfo->remote_addr
|
||||
, repinfo->remote_addrlen);
|
||||
if(worker_err_ratelimit(worker, LDNS_RCODE_REFUSED) == -1) {
|
||||
comm_point_drop_reply(repinfo);
|
||||
regional_free_all(worker->scratchpad);
|
||||
return 0;
|
||||
}
|
||||
EDNS_OPT_LIST_APPEND_EDE(&edns.opt_list_out,
|
||||
worker->scratchpad, LDNS_EDE_OTHER,
|
||||
"DNS Cookie needed for UDP replies");
|
||||
@@ -1783,14 +1820,14 @@ worker_handle_request(struct comm_point* c, void* arg, int error,
|
||||
verbose(VERB_ALGO, "worker request: edns is too small.");
|
||||
log_addr(VERB_CLIENT, "from", &repinfo->client_addr,
|
||||
repinfo->client_addrlen);
|
||||
LDNS_QR_SET(sldns_buffer_begin(c->buffer));
|
||||
if(worker_err_ratelimit(worker, LDNS_RCODE_SERVFAIL) == -1) {
|
||||
comm_point_drop_reply(repinfo);
|
||||
regional_free_all(worker->scratchpad);
|
||||
return 0;
|
||||
}
|
||||
/* A small error without qname, and TC flag on. */
|
||||
query_error(c->buffer, LDNS_RCODE_SERVFAIL, 0);
|
||||
LDNS_TC_SET(sldns_buffer_begin(c->buffer));
|
||||
LDNS_RCODE_SET(sldns_buffer_begin(c->buffer),
|
||||
LDNS_RCODE_SERVFAIL);
|
||||
sldns_buffer_set_position(c->buffer, LDNS_HEADER_SIZE);
|
||||
sldns_buffer_write_at(c->buffer, 4,
|
||||
(uint8_t*)"\0\0\0\0\0\0\0\0", 8);
|
||||
sldns_buffer_flip(c->buffer);
|
||||
regional_free_all(worker->scratchpad);
|
||||
goto send_reply;
|
||||
}
|
||||
@@ -1798,7 +1835,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);
|
||||
@@ -1875,6 +1918,15 @@ worker_handle_request(struct comm_point* c, void* arg, int error,
|
||||
* ACLs allow the snooping. */
|
||||
if(!(LDNS_RD_WIRE(sldns_buffer_begin(c->buffer))) &&
|
||||
acl != acl_allow_snoop ) {
|
||||
log_addr(VERB_ALGO, "refused nonrec (cache snoop) query from",
|
||||
&repinfo->client_addr, repinfo->client_addrlen);
|
||||
/* This ratelimited error query is accounted in the stats,
|
||||
* as an incoming query. */
|
||||
if(worker_err_ratelimit(worker, LDNS_RCODE_REFUSED) == -1) {
|
||||
comm_point_drop_reply(repinfo);
|
||||
regional_free_all(worker->scratchpad);
|
||||
return 0;
|
||||
}
|
||||
if(worker->env.cfg->ede) {
|
||||
EDNS_OPT_LIST_APPEND_EDE(&edns.opt_list_out,
|
||||
worker->scratchpad, LDNS_EDE_NOT_AUTHORITATIVE, "");
|
||||
@@ -1883,15 +1935,17 @@ worker_handle_request(struct comm_point* c, void* arg, int error,
|
||||
*(uint16_t*)(void *)sldns_buffer_begin(c->buffer),
|
||||
sldns_buffer_read_u16_at(c->buffer, 2), &edns);
|
||||
regional_free_all(worker->scratchpad);
|
||||
log_addr(VERB_ALGO, "refused nonrec (cache snoop) query from",
|
||||
&repinfo->client_addr, repinfo->client_addrlen);
|
||||
|
||||
goto send_reply;
|
||||
}
|
||||
|
||||
/* 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);
|
||||
@@ -1939,7 +1993,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
|
||||
@@ -2057,11 +2111,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,
|
||||
@@ -2076,7 +2129,7 @@ send_reply_rc:
|
||||
}
|
||||
}
|
||||
#ifdef USE_DNSCRYPT
|
||||
if(!dnsc_handle_uncurved_request(repinfo)) {
|
||||
if(!dnsc_handle_uncurved_request(repinfo, c->buffer)) {
|
||||
return 0;
|
||||
}
|
||||
#endif
|
||||
@@ -2124,10 +2177,37 @@ worker_restart_timer(struct worker* worker)
|
||||
{
|
||||
if(worker->env.cfg->stat_interval > 0) {
|
||||
struct timeval tv;
|
||||
if(worker->daemon->stat_time_specific) {
|
||||
struct timeval dest, now;
|
||||
int interval = worker->env.cfg->stat_interval;
|
||||
int offset = worker->daemon->stat_time_offset;
|
||||
int nows, spec;
|
||||
if(gettimeofday(&now, NULL) < 0)
|
||||
log_err("gettimeofday: %s", strerror(errno));
|
||||
#ifndef S_SPLINT_S
|
||||
tv.tv_sec = worker->env.cfg->stat_interval;
|
||||
tv.tv_usec = 0;
|
||||
nows = (int)now.tv_sec;
|
||||
/* The next time is on the timer interval, at the
|
||||
* specific offset, time value % interval = offset. */
|
||||
/* It relies on the integer division below to drop the
|
||||
* remainder in order to calculate the expected
|
||||
* result. */
|
||||
spec = ((nows-offset)/interval+1)*interval+offset;
|
||||
/* This is instead of an assertion, and should not
|
||||
* be needed. So assert(spec > nows), tv is going to
|
||||
* be positive. */
|
||||
if(spec<=nows) spec += interval;
|
||||
dest.tv_sec = spec;
|
||||
dest.tv_usec = 0;
|
||||
#endif
|
||||
/* Subtract in timeval, so the fractions of a second
|
||||
* are rounded to the whole specific time. */
|
||||
timeval_subtract(&tv, &dest, &now);
|
||||
} else {
|
||||
#ifndef S_SPLINT_S
|
||||
tv.tv_sec = worker->env.cfg->stat_interval;
|
||||
tv.tv_usec = 0;
|
||||
#endif
|
||||
}
|
||||
comm_timer_set(worker->stat_timer, &tv);
|
||||
}
|
||||
}
|
||||
@@ -2162,23 +2242,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;
|
||||
}
|
||||
@@ -2186,7 +2259,6 @@ 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;
|
||||
}
|
||||
@@ -2285,14 +2357,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);
|
||||
@@ -2311,6 +2383,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
|
||||
@@ -2443,7 +2517,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);
|
||||
@@ -2464,6 +2537,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);
|
||||
}
|
||||
|
||||
@@ -2472,7 +2547,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(
|
||||
@@ -2484,7 +2560,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;
|
||||
}
|
||||
@@ -2533,7 +2609,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;
|
||||
@@ -2575,6 +2652,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);
|
||||
|
||||
+1
-7
@@ -104,10 +104,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. */
|
||||
@@ -146,11 +142,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.
|
||||
|
||||
+59
-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
|
||||
@@ -998,6 +1027,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 +1050,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))
|
||||
|
||||
+32
-5
@@ -361,7 +361,7 @@ dnscrypt_server_uncurve(struct dnsc_env* env,
|
||||
|
||||
len -= DNSCRYPT_QUERY_HEADER_SIZE;
|
||||
|
||||
while (*sldns_buffer_at(buffer, --len) == 0)
|
||||
while (len>0 && *sldns_buffer_at(buffer, --len) == 0)
|
||||
;
|
||||
|
||||
if (*sldns_buffer_at(buffer, len) != 0x80) {
|
||||
@@ -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.
|
||||
|
||||
@@ -2133,6 +2133,8 @@ static void* dnstap_io(void* arg)
|
||||
struct dt_io_thread* dtio = (struct dt_io_thread*)arg;
|
||||
time_t secs = 0;
|
||||
struct timeval now;
|
||||
const char name[16] = "unbound/dnstap"; /* seems to be the safest size
|
||||
between different OSes */
|
||||
|
||||
#if defined(HAVE_GETTID) && !defined(THREADS_DISABLED)
|
||||
dtio->thread_tid = gettid();
|
||||
@@ -2142,6 +2144,8 @@ static void* dnstap_io(void* arg)
|
||||
#endif
|
||||
log_thread_set(&dtio->threadnum);
|
||||
|
||||
ub_thread_setname(ub_thread_self(), name);
|
||||
|
||||
/* setup */
|
||||
verbose(VERB_ALGO, "start dnstap io thread");
|
||||
dtio_setup_base(dtio, &secs, &now);
|
||||
|
||||
@@ -330,7 +330,7 @@ static struct tap_socket* tap_socket_new_tcpaccept(char* ip,
|
||||
/** create new socket (unconnected, not base-added), or NULL malloc fail */
|
||||
static struct tap_socket* tap_socket_new_tlsaccept(char* ip,
|
||||
void (*ev_cb)(int, short, void*), void* data, char* server_key,
|
||||
char* server_cert, char* verifypem)
|
||||
char* server_cert, char* verifypem, char* tls_protocols)
|
||||
{
|
||||
struct tap_socket* s = calloc(1, sizeof(*s));
|
||||
if(!s) {
|
||||
@@ -347,7 +347,7 @@ static struct tap_socket* tap_socket_new_tlsaccept(char* ip,
|
||||
s->ev_cb = ev_cb;
|
||||
s->data = data;
|
||||
s->sslctx = listen_sslctx_create(server_key, server_cert, verifypem,
|
||||
NULL, NULL, 0, 0, 0, 0);
|
||||
NULL, NULL, 0, 0, 0, tls_protocols);
|
||||
if(!s->sslctx) {
|
||||
log_err("could not create ssl context");
|
||||
free(s->ip);
|
||||
@@ -1261,13 +1261,13 @@ static void setup_tcp_list(struct main_tap_data* maindata,
|
||||
/** setup tls accept sockets */
|
||||
static void setup_tls_list(struct main_tap_data* maindata,
|
||||
struct config_strlist_head* tls_list, char* server_key,
|
||||
char* server_cert, char* verifypem)
|
||||
char* server_cert, char* verifypem, char* tls_protocols)
|
||||
{
|
||||
struct config_strlist* item;
|
||||
for(item = tls_list->first; item; item = item->next) {
|
||||
struct tap_socket* s;
|
||||
s = tap_socket_new_tlsaccept(item->str, &dtio_mainfdcallback,
|
||||
maindata, server_key, server_cert, verifypem);
|
||||
maindata, server_key, server_cert, verifypem, tls_protocols);
|
||||
if(!s) fatal_exit("out of memory");
|
||||
if(!tap_socket_list_insert(&maindata->acceptlist, s))
|
||||
fatal_exit("out of memory");
|
||||
@@ -1300,7 +1300,7 @@ static void
|
||||
setup_and_run(struct config_strlist_head* local_list,
|
||||
struct config_strlist_head* tcp_list,
|
||||
struct config_strlist_head* tls_list, char* server_key,
|
||||
char* server_cert, char* verifypem)
|
||||
char* server_cert, char* verifypem, char* tls_protocols)
|
||||
{
|
||||
time_t secs = 0;
|
||||
struct timeval now;
|
||||
@@ -1326,7 +1326,7 @@ setup_and_run(struct config_strlist_head* local_list,
|
||||
setup_local_list(maindata, local_list);
|
||||
setup_tcp_list(maindata, tcp_list);
|
||||
setup_tls_list(maindata, tls_list, server_key, server_cert,
|
||||
verifypem);
|
||||
verifypem, tls_protocols);
|
||||
if(!tap_socket_list_addevs(maindata->acceptlist, base))
|
||||
fatal_exit("could not setup accept events");
|
||||
if(verbosity) log_info("start of service");
|
||||
@@ -1462,6 +1462,8 @@ int main(int argc, char** argv)
|
||||
struct config_strlist_head tcp_list;
|
||||
struct config_strlist_head tls_list;
|
||||
char* server_key = NULL, *server_cert = NULL, *verifypem = NULL;
|
||||
|
||||
char* tls_protocols = "TLSv1.2 TLSv1.3";
|
||||
#ifdef USE_WINSOCK
|
||||
WSADATA wsa_data;
|
||||
if(WSAStartup(MAKEWORD(2,2), &wsa_data) != 0) {
|
||||
@@ -1561,17 +1563,25 @@ int main(int argc, char** argv)
|
||||
#else
|
||||
OPENSSL_init_crypto(OPENSSL_INIT_ADD_ALL_CIPHERS
|
||||
| OPENSSL_INIT_ADD_ALL_DIGESTS
|
||||
| OPENSSL_INIT_LOAD_CRYPTO_STRINGS, NULL);
|
||||
| OPENSSL_INIT_LOAD_CRYPTO_STRINGS
|
||||
# if defined(OPENSSL_INIT_NO_LOAD_CONFIG) && defined(UB_ON_WINDOWS)
|
||||
| OPENSSL_INIT_NO_LOAD_CONFIG
|
||||
# endif
|
||||
, NULL);
|
||||
#endif
|
||||
#if OPENSSL_VERSION_NUMBER < 0x10100000 || !defined(HAVE_OPENSSL_INIT_SSL)
|
||||
(void)SSL_library_init();
|
||||
#else
|
||||
(void)OPENSSL_init_ssl(OPENSSL_INIT_LOAD_SSL_STRINGS, NULL);
|
||||
(void)OPENSSL_init_ssl(OPENSSL_INIT_LOAD_SSL_STRINGS
|
||||
# if defined(OPENSSL_INIT_NO_LOAD_CONFIG) && defined(UB_ON_WINDOWS)
|
||||
| OPENSSL_INIT_NO_LOAD_CONFIG
|
||||
# endif
|
||||
, NULL);
|
||||
#endif
|
||||
#endif /* HAVE_SSL */
|
||||
}
|
||||
setup_and_run(&local_list, &tcp_list, &tls_list, server_key,
|
||||
server_cert, verifypem);
|
||||
server_cert, verifypem, tls_protocols);
|
||||
config_delstrlist(local_list.first);
|
||||
config_delstrlist(tcp_list.first);
|
||||
config_delstrlist(tls_list.first);
|
||||
@@ -1649,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;
|
||||
@@ -1683,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;
|
||||
@@ -1725,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);
|
||||
|
||||
+912
@@ -1,3 +1,915 @@
|
||||
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.
|
||||
- Fix CVE-2026-42944, Heap overflow and crash with multiple nsid,
|
||||
cookie, padding EDNS options. Thanks to Qifan Zhang, Palo Alto
|
||||
Networks, for the report.
|
||||
- Fix CVE-2026-42959, Crash during DNSSEC validation of malicious
|
||||
content. Thanks to Qifan Zhang, Palo Alto Networks, for the report.
|
||||
- Fix CVE-2026-32792, Packet of death with DNSCrypt. Thanks to Andrew
|
||||
Griffiths from 'calif.io' for the report.
|
||||
- Fix CVE-2026-40622, "Ghost domain name" variant. Thanks to Qifan
|
||||
Zhang, Palo Alto Networks, for the report.
|
||||
- Fix CVE-2026-41292, Parsing a long list of incoming EDNS options
|
||||
degrades performance. Thanks to GitHub user 'N0zoM1z0', also Qifan
|
||||
Zhang from Palo Alto Networks, for the report.
|
||||
- Fix CVE-2026-42534, Jostle logic bypass degrades resolution
|
||||
performance. Thanks to Qifan Zhang, Palo Alto Networks, for the
|
||||
report.
|
||||
- Fix CVE-2026-42923, Degradation of service with unbounded NSEC3
|
||||
hash calculations. Thanks to Qifan Zhang, Palo Alto Networks, for
|
||||
the report.
|
||||
- Fix CVE-2026-42960, Possible cache poisoning attack while following
|
||||
delegation. Thanks to TaoFei Guo from Peking University, Yang Luo
|
||||
and JianJun Chen, Tsinghua University, for the report.
|
||||
- Fix CVE-2026-44390, Unbounded name compression in certain cases
|
||||
causes degradation of service. Thanks to Qifan Zhang, Palo Alto
|
||||
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
|
||||
doq_repinfo_retrieve_localaddr().
|
||||
- For #1441: Fix type of ipv6 addr struct.
|
||||
|
||||
21 April 2026: Wouter
|
||||
- Add test case for malformed SVCB records. Thanks to
|
||||
Qifan Zhang, Palo Alto Networks for the additional test.
|
||||
- Fix for the Jiggle Attack. The server is fixed to answer
|
||||
with errors for error cases, and does not stay silent.
|
||||
In addition, the error replies do not contain parts of the
|
||||
incoming query. This is more conformant, stops reflection
|
||||
and stops it as a covert channel. Thanks to Yuqi Qiu and
|
||||
Xiang Li, Nankai University (AOSP Lab) for the report.
|
||||
In addition, thanks to Qifan Zhang, Palo Alto Networks, for
|
||||
noting the fingerprinting possibility, that is also fixed
|
||||
with this.
|
||||
- Fix EDNS extended RCODE reflection. This fixes that
|
||||
the server does not echo extended rcode values after class
|
||||
chaos queries. Thanks to Qifan Zhang, Palo Alto Networks
|
||||
for the report.
|
||||
- Fix for iterator RCODE handling of YXDOMAIN. This fixes
|
||||
that the server only accepts YXDOMAIN answers that contain
|
||||
a DNAME record. This stops bad answers, and checks that
|
||||
the authoritative server gives correct replies.
|
||||
Thanks to Qifan Zhang, Palo Alto Networks for the report.
|
||||
- Fix for missing bounds check for decompressing dnames
|
||||
for downloaded authority zones. This fixes that the server
|
||||
could end up with malformed zone content after receiving
|
||||
truncated packet contents from an AXFR. In addition, the
|
||||
domain names in the SOA rdata are checked before the
|
||||
authority code picks up the zone serial.
|
||||
Thanks to Halil Oktay for the report.
|
||||
- Fix that upstream TLS connections are not reused as TLS
|
||||
connections for a different name, at the same IP. This
|
||||
checks that the tls name is correct when reusing the
|
||||
upstream connections. Thanks to TaoFei Guo from Peking
|
||||
University and JianJun Chen from Tsinghua University for
|
||||
the report.
|
||||
- Fix that signatures are not allowed with revoked dnskeys.
|
||||
Thanks to Qifan Zhang, Palo Alto Networks for the report.
|
||||
- Fix that a DNAME with an unsigned CNAME is checked for
|
||||
the correct match. This stops that for certain zone
|
||||
configurations an unchecked unsigned CNAME could get
|
||||
secure status. Thanks to Qifan Zhang, Palo Alto Networks
|
||||
for the report.
|
||||
- Fix handling of wildcard CNAMEs in the chain of trust.
|
||||
An improper wildcard in the chain of trust would send
|
||||
the retries to the wrong upstream. Also it could label
|
||||
the step in the chain of trust as secure, when it was not.
|
||||
Thanks to Qifan Zhang, Palo Alto Networks for the report.
|
||||
- Set version number to 1.25.0 of code repository.
|
||||
- Fix doxygen comment syntax.
|
||||
|
||||
20 April 2026: Wouter
|
||||
- Fix compile warnings for thread setname routine, and test compile.
|
||||
- Fix unused variable warning when compiled without ssl.
|
||||
- Fix test with https zone for libressl.
|
||||
|
||||
17 April 2026: Wouter
|
||||
- Fix setup of ssl context copy of the tls service pem option,
|
||||
from a clang analyzer warning.
|
||||
- Fix setup of ssl context copy, to check for the tls service
|
||||
pem option for stat calls.
|
||||
- Fix to compile the shm code when there is no shmget.
|
||||
- Update github ci to use actions/checkout@v6.
|
||||
- Update github ci cross platform to use
|
||||
cross-platform-actions/action@v1.0.0.
|
||||
- Fix github ci to speed up with parralel build, for windows ci.
|
||||
- Fix compat/chacha_private sigma and tau definitions to use
|
||||
nonstring attribute.
|
||||
- Fix compat/gmtime_r old style definition syntax.
|
||||
- Fix to increase size of the buffer for the win_svc reportev log
|
||||
function.
|
||||
- Fix ttl comparisons in rdata_copy for 32bit signed or unsigned.
|
||||
- Fix subnet store of servfail to not leak memory.
|
||||
- Update generated man pages.
|
||||
- Update generated configure, with autoconf.
|
||||
- Fix pthread_setname detection to fail on warnings.
|
||||
|
||||
17 April 2026: Yorgos
|
||||
- Merge #1400: Support pthread_setname_np. Adds support for
|
||||
pthread_setname_np and variants to set the name on spawned threads
|
||||
for easier debugging/monitoring.
|
||||
|
||||
16 April 2026: Yorgos
|
||||
- Merge #1406: Introduce new 'tls-protocols' configuration option.
|
||||
- Introduce new 'tls-protocols' configuration option that specifies
|
||||
which of the supported TLS protocols will be used.
|
||||
This change invalidates some previous changes:
|
||||
- TLSv1.2 is again enabled by default, but can be selectively turned
|
||||
off if desired (related to #1303).
|
||||
- The biefly introduced (not yet released) 'tls-use-system-versions'
|
||||
configuration option, that addressed #1346, is reverted in favor of
|
||||
'tls-protocols'.
|
||||
- The briefly introduced (not yet released) '--enable-system-tls'
|
||||
configure option, related to #1401, is no longer needed with the new
|
||||
option and the current default.
|
||||
- Fix cleaning up DoH session. The same query can be on multiple
|
||||
streams in a session.
|
||||
|
||||
16 April 2026: Wouter
|
||||
- Fix configure, autoconf for #1406.
|
||||
|
||||
15 April 2026: Wouter
|
||||
- Fix RFC7766 compliance when client sends EOF over TCP. It stops
|
||||
pending replies and closes. Thanks to Yuxiao Wu, Tsinghua
|
||||
University for the report.
|
||||
- Fix to shorten RRSIG count in scrubber, this protects against
|
||||
an overly large number of RRSIGs. It can be configured with
|
||||
`iter-scrub-rrsig: 8`, it has default 8. Thanks to Yuxiao Wu,
|
||||
Tsinghua University for the report.
|
||||
|
||||
14 April 2026: Wouter
|
||||
- Fix #1017: memory corruption related core dumps.
|
||||
When alloc_reg_obtain has an empty list, return a new allocation.
|
||||
- Fix clang analyzer warning for subnetmod, when return_msg is
|
||||
NULL for update cache, like when it stores servfail status.
|
||||
- iana portlist updated.
|
||||
|
||||
13 April 2026: Yorgos
|
||||
- Update the documentation of 'max-query-restarts' in the man page.
|
||||
|
||||
10 April 2026: Wouter
|
||||
- Fix for EDNS client subnet so that it does not store SERVFAIL in
|
||||
the global cache after a failed lookup, such as timeouts. A failure
|
||||
entry is stored in the subnet cache, for the query name, for a
|
||||
couple of seconds. Queries can continue to use the subnet cache
|
||||
during that time.
|
||||
|
||||
7 April 2026: Yorgos
|
||||
- Fix unused variable warning.
|
||||
|
||||
30 March 2026: Wouter
|
||||
- Merge #1408: Fix shared memory stats with threads.
|
||||
|
||||
27 March 2026: Wouter
|
||||
- Fix to allow the control-interface config to use ip@port notation.
|
||||
- Fix test code to allow empty hex answer packets from testbound.
|
||||
- Fix defense in depth for service callback with empty packet.
|
||||
|
||||
24 March 2026: Wouter
|
||||
- Fix to check for invalid http content length and chunk size,
|
||||
and to check the RR rdata field lengths when decompressing and
|
||||
inserting RRs from an authority zone transfer. This stops
|
||||
large memory use and heap buffer-overflow read errors. Thanks
|
||||
to Haruto Kimura (Stella) for the report.
|
||||
|
||||
20 March 2026: Wouter
|
||||
- Fix for testcode pktview to check buffer size and log errors.
|
||||
|
||||
13 March 2026: Yorgos
|
||||
- Fix to ignore out-of-zone DNAME records for CNAME synthesis. Thanks
|
||||
to Yuxiao Wu, Yiyi Wang, Zhang Chao, Baojun Liu, and Haixin Duan from
|
||||
Tsinghua University.
|
||||
|
||||
13 March 2026: Wouter
|
||||
- Fix #278: DoT: complete unbound restart required on certificate
|
||||
renew. Fix so that a reload checks if the files have changed, and
|
||||
if so, reload the contexts. Also for DoH, DoQ and outgoing DoT.
|
||||
- iana portlist updated.
|
||||
- For #278: fast_reload can reload tls-service-key, tls-service-pem
|
||||
and tls-cert-bundle changes. It checks the modification time of
|
||||
the tls-service-key and tls-service-pem files for update.
|
||||
- Fix detection of http listening port in fast_reload.
|
||||
- Fix to add tls-service-key to memory printout for fast_reload.
|
||||
|
||||
9 March 2026: Wouter
|
||||
- Fix compile failure in unbound-checkconf for older gcc compiler.
|
||||
- Merge #1418: Apply cache TTL policy to DNAME and synthesized
|
||||
CNAME on wire path.
|
||||
|
||||
6 March 2026: Wouter
|
||||
- Merge #1415: Add lock unlock for view in memory error handling.
|
||||
|
||||
6 March 2026: Yorgos
|
||||
- Document the suggestion for a higher value for 'outgoing-range';
|
||||
helps when the request list is full.
|
||||
- Warn for unused 'nodefault' local-zone configuration in
|
||||
unbound-checkconf (related to #1416).
|
||||
|
||||
5 March 2026: Wouter
|
||||
- Fix for DNS Rebinding Bypass via SVCB/HTTPS Records in Unbound.
|
||||
Thanks to Kunta Chu, School of Software, Tsinghua University,
|
||||
Taofei Guo, Peking University, and Jianjun Chen, Institute for
|
||||
Network Sciences and Cyberspace, Tsinghua University for the
|
||||
report. The private-address option is fixed to also elide
|
||||
SVCB and HTTPS records that match the filter.
|
||||
- Update generated man pages.
|
||||
|
||||
4 March 2026: Yorgos
|
||||
- For #1411: Introduce a failing case in the rpl test so that it only
|
||||
passes with the fix in place.
|
||||
|
||||
3 March 2026: Wouter
|
||||
- Merge #1411: Allow synthesized DNAME TTL=0 to be served from cache
|
||||
within grace period. The responses are served from cache within
|
||||
a 1-second grace period. Reduces recursion when authoritative
|
||||
servers return DNAME with TTL=0 (RFC 2308). Response
|
||||
still returns TTL=0 to clients. Adds a test for it.
|
||||
- For #1411: Fix that the lookup for DNAME uses flag. Fix assertion
|
||||
in expired calc debug routine.
|
||||
|
||||
27 February 2026: Wouter
|
||||
- Merge #1409: Documentation CNAME in redirect-type local-zone.
|
||||
- Update generated man pages.
|
||||
|
||||
25 February 2026: Wouter
|
||||
- Fix validator to set unchecked when validation recursion
|
||||
requests are passed. The edns subnet module checks if validation
|
||||
is needed for a cache response, and set the validator to protect
|
||||
the cache with validation for non-subnet lookups.
|
||||
|
||||
23 February 2026: Wouter
|
||||
- Fix to have cachedb not return expired bogus data as non-bogus.
|
||||
- Fix to make the cachedb_val_expired.crpl succeed.
|
||||
|
||||
23 February 2026: Yorgos
|
||||
- Fix to disallow cache lookup/store in external cachedb when a
|
||||
forwarder/stub forbids it with the no-cache option.
|
||||
- Fixed some typos reported in #1395 by rezky_nightky.
|
||||
|
||||
17 February 2026: Wouter
|
||||
- Fix to remove unused conditional from cookie timestamp at
|
||||
worker env.
|
||||
- For #1405: local-zone always_refuse also blocks queries of type DS.
|
||||
|
||||
16 February 2026: Yorgos
|
||||
- Fix #1404: Priming the root key fails after loading ipfire.org RPZ
|
||||
zones. Fixed by including the ZONEMD RRtype in the list of types to
|
||||
ignore for RPZ zones. Analysis and patch provided by ummeegge.
|
||||
|
||||
16 February 2026: Wouter
|
||||
- Fix that cachedb aggressive negative responses have the RA flag set.
|
||||
|
||||
11 February 2026: Wouter
|
||||
- Fix #1403: Inconsistency between do-nat64 and do-not-query-address
|
||||
during retries.
|
||||
|
||||
9 February 2026: Wouter
|
||||
- Merge #1401: Add a new build-time option for system TLS.
|
||||
The --enable-system-tls flag enables the
|
||||
tls-use-system-policy-versions setting by default.
|
||||
- Update generated man pages.
|
||||
|
||||
6 February 2026: Yorgos
|
||||
- Fix #1389: [FR] replacement with ECC-GOST12 according to RFC9558.
|
||||
Patch contributed by Igor V. Ruzanov, available in
|
||||
contrib/gost12.patch.
|
||||
|
||||
4 February 2026: Wouter
|
||||
- Fix local privilege escalation on Windows. Thanks to Hao Huang and
|
||||
CrisprXiang with Fudan University for the report. The OpenSSL
|
||||
init calls are set to not load the openssl.cnf file when compiled
|
||||
for Windows.
|
||||
|
||||
3 February 2026: Yorgos
|
||||
- Eagerly remove .skip mark files in between mini_tdir.sh runs in case
|
||||
there has been a change on the environment.
|
||||
|
||||
27 January 2026: Wouter
|
||||
- Add test for allow-notify with a host name.
|
||||
|
||||
|
||||
+18
-10
@@ -193,6 +193,9 @@ server:
|
||||
# Limit on number of CNAME, DNAME records for incoming packets.
|
||||
# iter-scrub-cname: 11
|
||||
|
||||
# Limit on number of RRSIGs for an RRset for incoming packets.
|
||||
# iter-scrub-rrsig: 8
|
||||
|
||||
# Limit on upstream queries for an incoming query and its recursion.
|
||||
# max-global-quota: 200
|
||||
|
||||
@@ -662,7 +665,7 @@ server:
|
||||
# or, just before the iterator).
|
||||
# module-config: "validator iterator"
|
||||
|
||||
# File with trusted keys, kept uptodate using RFC5011 probes,
|
||||
# File with trusted keys, kept up-to-date using RFC5011 probes,
|
||||
# initial file like trust-anchor-file, then it stores metadata.
|
||||
# Use several entries, one per domain name, to track multiple zones.
|
||||
#
|
||||
@@ -722,7 +725,7 @@ server:
|
||||
# val-max-restart: 5
|
||||
|
||||
# Should additional section of secure message also be kept clean of
|
||||
# unsecure data. Useful to shield the users of this validator from
|
||||
# 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
|
||||
@@ -896,6 +899,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.
|
||||
#
|
||||
@@ -965,16 +972,12 @@ server:
|
||||
# tls-ciphersuites: "TLS_AES_128_GCM_SHA256:TLS_AES_128_CCM_8_SHA256:TLS_AES_128_CCM_SHA256:TLS_AES_256_GCM_SHA384:TLS_CHACHA20_POLY1305_SHA256"
|
||||
|
||||
# Use the SNI extension for TLS connections. Default is yes.
|
||||
# Changing the value requires a reload.
|
||||
# Changing the value requires a restart.
|
||||
# tls-use-sni: yes
|
||||
|
||||
# Allow general-purpose version-flexible TLS server configuration that
|
||||
# may be further restricted by the system's policy.
|
||||
# Use only if you want to support legacy TLS client connections.
|
||||
# Default is no and Unbound will only use the latest available TLS
|
||||
# version.
|
||||
# Changing the value requires a reload.
|
||||
# tls-use-system-policy-versions: no
|
||||
# TLS protocols.
|
||||
# Changing the value requires a restart.
|
||||
# tls-protocols: "TLSv1.2 TLSv1.3"
|
||||
|
||||
# Add the secret file for TLS Session Ticket.
|
||||
# Secret file must be 80 bytes of random data.
|
||||
@@ -1288,6 +1291,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.
|
||||
@@ -1454,3 +1460,5 @@ remote-control:
|
||||
# rpz-signal-nxdomain-ra: no
|
||||
# for-downstream: no
|
||||
# tags: "example"
|
||||
# max-transfer-size: 0
|
||||
# max-transfer-time: 0
|
||||
|
||||
@@ -168,6 +168,8 @@ ipset,
|
||||
\fI\%tcp\-auth\-query\-timeout\fP,
|
||||
\fI\%delay\-close\fP\&.
|
||||
\fI\%iter\-scrub\-promiscuous\fP\&.
|
||||
\fI\%tls\-service\-key\fP\&.
|
||||
\fI\%tls\-service\-pem\fP\&.
|
||||
.sp
|
||||
It does not work with
|
||||
\fI\%interface\fP and
|
||||
@@ -352,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
|
||||
|
||||
@@ -170,6 +170,8 @@ There are several commands that the server understands.
|
||||
:ref:`tcp-auth-query-timeout<unbound.conf.tcp-auth-query-timeout>`,
|
||||
:ref:`delay-close<unbound.conf.delay-close>`.
|
||||
:ref:`iter-scrub-promiscuous<unbound.conf.iter-scrub-promiscuous>`.
|
||||
:ref:`tls-service-key<unbound.conf.tls-service-key>`.
|
||||
:ref:`tls-service-pem<unbound.conf.tls-service-pem>`.
|
||||
|
||||
It does not work with
|
||||
:ref:`interface<unbound.conf.interface>` and
|
||||
@@ -345,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@@
|
||||
|
||||
+192
-23
@@ -382,6 +382,10 @@ Default depends on compile options.
|
||||
Larger numbers need extra resources from the operating system.
|
||||
For performance a very large value is best, use libevent to make this
|
||||
possible.
|
||||
Should be higher (preferably double) than the value of
|
||||
\fI\%num\-queries\-per\-thread\fP to
|
||||
account for cases where the request list is full and avoid file descriptor
|
||||
starvation.
|
||||
.sp
|
||||
Default: 4096 (libevent) / 960 (minievent) / 48 (windows)
|
||||
.UNINDENT
|
||||
@@ -687,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
|
||||
@@ -1135,9 +1139,13 @@ The file must contain the private key for the TLS session, the public
|
||||
certificate is in the \fI\%tls\-service\-pem\fP
|
||||
file and it must also be specified if
|
||||
\fI\%tls\-service\-key\fP is specified.
|
||||
Enabling or disabling this service requires a restart (a reload is not
|
||||
enough), because the key is read while root permissions are held and before
|
||||
chroot (if any).
|
||||
If the key is stored with root permissions or outside of chroot, then
|
||||
a change or enabling or disabling requires a restart (a reload is not
|
||||
enough).
|
||||
But if the key file (and tls\-service\-pem file) are accessible, then they
|
||||
are read in on reload, and fast_reload.
|
||||
The server checks the modification time of the file (and the filename)
|
||||
to see if the file has changed for reload.
|
||||
The ports enabled implicitly or explicitly via
|
||||
\fI\%tls\-port\fP and
|
||||
\fI\%https\-port\fP do not provide normal DNS TCP
|
||||
@@ -1290,7 +1298,7 @@ Enable or disable sending the SNI extension on TLS connections.
|
||||
\fBNOTE:\fP
|
||||
.INDENT 7.0
|
||||
.INDENT 3.5
|
||||
Changing the value requires a reload.
|
||||
Changing the value requires a restart.
|
||||
.UNINDENT
|
||||
.UNINDENT
|
||||
.sp
|
||||
@@ -1298,30 +1306,19 @@ Default: yes
|
||||
.UNINDENT
|
||||
.INDENT 0.0
|
||||
.TP
|
||||
.B tls\-use\-system\-policy\-versions: \fI<yes or no>\fP
|
||||
Enable or disable general\-puspose version\-flexible TLS server configuration
|
||||
when serving TLS.
|
||||
This will allow the whole list of available TLS versions provided by the
|
||||
crypto library, which may have been further restricted by the system\(aqs
|
||||
crypto policy.
|
||||
.sp
|
||||
By default Unbound only uses the latest available TLS version.
|
||||
.sp
|
||||
\fBCAUTION:\fP
|
||||
.INDENT 7.0
|
||||
.INDENT 3.5
|
||||
Use only if you want to support legacy TLS client connections.
|
||||
.UNINDENT
|
||||
.UNINDENT
|
||||
.B tls\-protocols: \fI\(dq<list of protocols>\(dq\fP
|
||||
Specify the allowed TLS protocol versions to use, in no particular order.
|
||||
Possible values are \fBTLSv1.2\fP and \fBTLSv1.3\fP\&.
|
||||
Enclose list of protocols in quotes (\fB\(dq\(dq\fP) and put spaces between them.
|
||||
.sp
|
||||
\fBNOTE:\fP
|
||||
.INDENT 7.0
|
||||
.INDENT 3.5
|
||||
Changing the value requires a reload.
|
||||
Changing the value requires a restart.
|
||||
.UNINDENT
|
||||
.UNINDENT
|
||||
.sp
|
||||
Default: no
|
||||
Default: \(dqTLSv1.2 TLSv1.3\(dq
|
||||
.UNINDENT
|
||||
.INDENT 0.0
|
||||
.TP
|
||||
@@ -2272,6 +2269,11 @@ This protects against so\-called DNS Rebinding, where a user browser is
|
||||
turned into a network proxy, allowing remote access through the browser to
|
||||
other parts of your private network.
|
||||
.sp
|
||||
The option removes resource records of types A, AAAA, SVCB and HTTPS
|
||||
that match the filter.
|
||||
Inside the SVCB and HTTPS records, the svcparams of type ipv4hint
|
||||
and ipv6hint are checked for matches.
|
||||
.sp
|
||||
Some names can be allowed to contain your private addresses, by default all
|
||||
the \fI\%local\-data\fP that you configured is
|
||||
allowed to, and you can specify additional names using
|
||||
@@ -2310,6 +2312,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
|
||||
@@ -2360,6 +2369,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
|
||||
@@ -2908,6 +2919,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,
|
||||
@@ -3010,6 +3024,39 @@ local\-data: \(dqexample.com. A 127.0.0.1\(dq
|
||||
queries for \fBwww.example.com\fP and \fBwww.foo.example.com\fP are
|
||||
redirected, so that users with web browsers cannot access sites with
|
||||
suffix example.com.
|
||||
.sp
|
||||
A \fBCNAME\fP record can also be provided via local\-data:
|
||||
.INDENT 7.0
|
||||
.INDENT 3.5
|
||||
.sp
|
||||
.nf
|
||||
.ft C
|
||||
local\-zone: \(dqexample.com.\(dq redirect
|
||||
local\-data: \(dqexample.com. CNAME www.example.org.\(dq
|
||||
.ft P
|
||||
.fi
|
||||
.UNINDENT
|
||||
.UNINDENT
|
||||
.sp
|
||||
In that case, the \fBCNAME\fP is resolved and the answer
|
||||
includes resolved target records as well.
|
||||
The \fBCNAME\fP record has to be with the zone name of the local\-zone,
|
||||
and there can be one CNAME, not more.
|
||||
The \fBCNAME\fP record has to be at the zone apex of the
|
||||
\fBredirect\fP zone, then it is used for redirection.
|
||||
The resolution proceeds with upstream DNS resolution, and
|
||||
that does not include the lookup in local zones.
|
||||
So the record is not able to point in local zones, but it
|
||||
can point to upstream DNS answers.
|
||||
.sp
|
||||
\fBCNAME\fP resolution is supported only in type \fBredirect\fP
|
||||
local\-zone, and in type \fBinform_redirect\fP local\-zone.
|
||||
.sp
|
||||
As different from \fBCNAME\fP records that are used elsewhere, in
|
||||
the \fBredirect\fP type local\-zone, it is supported that in the target
|
||||
of the record a wildcard label gets expanded to the query name, with
|
||||
for example: \fBexample.com. CNAME *.foo.net.\fP gets expanded
|
||||
to \fBwww.example.com. CNAME www.example.com.foo.net.\fP\&.
|
||||
.UNINDENT
|
||||
.INDENT 7.0
|
||||
.TP
|
||||
@@ -3065,9 +3112,38 @@ 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.
|
||||
This type also blocks queries of type DS for the zone name.
|
||||
That can break the DNSSEC chain of trust, but it is refused anyway.
|
||||
The block for type DS assists in more completely blocking the zone.
|
||||
.UNINDENT
|
||||
.INDENT 7.0
|
||||
.TP
|
||||
@@ -3529,6 +3605,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
|
||||
@@ -3731,6 +3819,10 @@ Default: 32
|
||||
Hard limit on the number of times Unbound is allowed to restart a query
|
||||
upon encountering a CNAME record.
|
||||
Results in SERVFAIL when reached.
|
||||
This applies to chained CNAME records but not sporadic CNAME records that
|
||||
could be encountered in the lifetime of the query\(aqs resolution effort.
|
||||
When a CNAME chain concludes, the counter keeping track of this limit is
|
||||
reset.
|
||||
Changing this value needs caution as it can allow long CNAME chains to be
|
||||
accepted, where Unbound needs to verify (resolve) each link individually.
|
||||
.sp
|
||||
@@ -3758,6 +3850,16 @@ Default: 11
|
||||
.UNINDENT
|
||||
.INDENT 0.0
|
||||
.TP
|
||||
.B iter\-scrub\-rrsig: \fI<number>\fP
|
||||
Limit on the number of RRSIGs allowed for an RRset, from the iterator
|
||||
scrubber.
|
||||
This protects against an overly large number of RRSIGs.
|
||||
Clips off the remainder of the RRSIG list at that point.
|
||||
.sp
|
||||
Default: 8
|
||||
.UNINDENT
|
||||
.INDENT 0.0
|
||||
.TP
|
||||
.B max\-global\-quota: \fI<number>\fP
|
||||
Limit on the number of upstream queries sent out for an incoming query and
|
||||
its subqueries from recursion.
|
||||
@@ -3939,7 +4041,7 @@ Default: no
|
||||
.UNINDENT
|
||||
.INDENT 0.0
|
||||
.TP
|
||||
.B control\-interface: \fI<IP address or interface name or path>\fP
|
||||
.B control\-interface: \fI<IP address or interface name[@port] or path>\fP
|
||||
Give IPv4 or IPv6 addresses or local socket path to listen on for control
|
||||
commands.
|
||||
If an interface name is used instead of an IP address, the list of IP
|
||||
@@ -4542,6 +4644,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.
|
||||
@@ -4756,6 +4884,17 @@ Default: no
|
||||
Use a specific NAT64 prefix to reach IPv4\-only servers.
|
||||
The prefix length must be one of /32, /40, /48, /56, /64 or /96.
|
||||
.sp
|
||||
The NAT64 prefix is allowed by the
|
||||
\fI\%do\-not\-query\-address\fP option,
|
||||
so that there is a clear outcome of addresses in both; the NAT64 prefix
|
||||
is allowed.
|
||||
The IPv4 address could be filtered by the
|
||||
\fI\%do\-not\-query\-address\fP option,
|
||||
if needed.
|
||||
Allowing the NAT64 prefix is useful when using do\-not\-query\-address
|
||||
for a cluster of machines that is IPv6\-only and uses NAT64, but does
|
||||
not have internet access.
|
||||
.sp
|
||||
Default: 64:ff9b::/96 (same as \fI\%dns64\-prefix\fP)
|
||||
.UNINDENT
|
||||
.SH DNSCRYPT OPTIONS
|
||||
@@ -5743,6 +5882,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
|
||||
@@ -5865,6 +6008,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.
|
||||
|
||||
+177
-18
@@ -366,6 +366,10 @@ These options are part of the ``server:`` section.
|
||||
Larger numbers need extra resources from the operating system.
|
||||
For performance a very large value is best, use libevent to make this
|
||||
possible.
|
||||
Should be higher (preferably double) than the value of
|
||||
:ref:`num-queries-per-thread<unbound.conf.num-queries-per-thread>` to
|
||||
account for cases where the request list is full and avoid file descriptor
|
||||
starvation.
|
||||
|
||||
Default: 4096 (libevent) / 960 (minievent) / 48 (windows)
|
||||
|
||||
@@ -638,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
|
||||
@@ -1044,9 +1048,13 @@ These options are part of the ``server:`` section.
|
||||
certificate is in the :ref:`tls-service-pem<unbound.conf.tls-service-pem>`
|
||||
file and it must also be specified if
|
||||
:ref:`tls-service-key<unbound.conf.tls-service-key>` is specified.
|
||||
Enabling or disabling this service requires a restart (a reload is not
|
||||
enough), because the key is read while root permissions are held and before
|
||||
chroot (if any).
|
||||
If the key is stored with root permissions or outside of chroot, then
|
||||
a change or enabling or disabling requires a restart (a reload is not
|
||||
enough).
|
||||
But if the key file (and tls-service-pem file) are accessible, then they
|
||||
are read in on reload, and fast_reload.
|
||||
The server checks the modification time of the file (and the filename)
|
||||
to see if the file has changed for reload.
|
||||
The ports enabled implicitly or explicitly via
|
||||
:ref:`tls-port<unbound.conf.tls-port>` and
|
||||
:ref:`https-port<unbound.conf.https-port>` do not provide normal DNS TCP
|
||||
@@ -1172,25 +1180,19 @@ These options are part of the ``server:`` section.
|
||||
@@UAHL@unbound.conf@tls-use-sni@@: *<yes or no>*
|
||||
Enable or disable sending the SNI extension on TLS connections.
|
||||
|
||||
.. note:: Changing the value requires a reload.
|
||||
.. note:: Changing the value requires a restart.
|
||||
|
||||
Default: yes
|
||||
|
||||
|
||||
@@UAHL@unbound.conf@tls-use-system-policy-versions@@: *<yes or no>*
|
||||
Enable or disable general-puspose version-flexible TLS server configuration
|
||||
when serving TLS.
|
||||
This will allow the whole list of available TLS versions provided by the
|
||||
crypto library, which may have been further restricted by the system's
|
||||
crypto policy.
|
||||
@@UAHL@unbound.conf@tls-protocols@@: *"<list of protocols>"*
|
||||
Specify the allowed TLS protocol versions to use, in no particular order.
|
||||
Possible values are ``TLSv1.2`` and ``TLSv1.3``.
|
||||
Enclose list of protocols in quotes (``""``) and put spaces between them.
|
||||
|
||||
By default Unbound only uses the latest available TLS version.
|
||||
.. note:: Changing the value requires a restart.
|
||||
|
||||
.. caution:: Use only if you want to support legacy TLS client connections.
|
||||
|
||||
.. note:: Changing the value requires a reload.
|
||||
|
||||
Default: no
|
||||
Default: "TLSv1.2 TLSv1.3"
|
||||
|
||||
|
||||
@@UAHL@unbound.conf@pad-responses@@: *<yes or no>*
|
||||
@@ -2012,6 +2014,11 @@ These options are part of the ``server:`` section.
|
||||
turned into a network proxy, allowing remote access through the browser to
|
||||
other parts of your private network.
|
||||
|
||||
The option removes resource records of types A, AAAA, SVCB and HTTPS
|
||||
that match the filter.
|
||||
Inside the SVCB and HTTPS records, the svcparams of type ipv4hint
|
||||
and ipv6hint are checked for matches.
|
||||
|
||||
Some names can be allowed to contain your private addresses, by default all
|
||||
the :ref:`local-data<unbound.conf.local-data>` that you configured is
|
||||
allowed to, and you can specify additional names using
|
||||
@@ -2048,6 +2055,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)
|
||||
|
||||
|
||||
@@ -2093,6 +2107,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
|
||||
|
||||
@@ -2576,6 +2592,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>`,
|
||||
@@ -2662,6 +2681,33 @@ These options are part of the ``server:`` section.
|
||||
redirected, so that users with web browsers cannot access sites with
|
||||
suffix example.com.
|
||||
|
||||
A ``CNAME`` record can also be provided via local-data:
|
||||
|
||||
.. code-block:: text
|
||||
|
||||
local-zone: "example.com." redirect
|
||||
local-data: "example.com. CNAME www.example.org."
|
||||
|
||||
In that case, the ``CNAME`` is resolved and the answer
|
||||
includes resolved target records as well.
|
||||
The ``CNAME`` record has to be with the zone name of the local-zone,
|
||||
and there can be one CNAME, not more.
|
||||
The ``CNAME`` record has to be at the zone apex of the
|
||||
``redirect`` zone, then it is used for redirection.
|
||||
The resolution proceeds with upstream DNS resolution, and
|
||||
that does not include the lookup in local zones.
|
||||
So the record is not able to point in local zones, but it
|
||||
can point to upstream DNS answers.
|
||||
|
||||
``CNAME`` resolution is supported only in type ``redirect``
|
||||
local-zone, and in type ``inform_redirect`` local-zone.
|
||||
|
||||
As different from ``CNAME`` records that are used elsewhere, in
|
||||
the ``redirect`` type local-zone, it is supported that in the target
|
||||
of the record a wildcard label gets expanded to the query name, with
|
||||
for example: ``example.com. CNAME *.foo.net.`` gets expanded
|
||||
to ``www.example.com. CNAME www.example.com.foo.net.``.
|
||||
|
||||
@@UAHL@unbound.conf.local-zone.type@inform@@
|
||||
The query is answered normally, same as
|
||||
:ref:`transparent<unbound.conf.local-zone.type.transparent>`.
|
||||
@@ -2698,9 +2744,32 @@ 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.
|
||||
This type also blocks queries of type DS for the zone name.
|
||||
That can break the DNSSEC chain of trust, but it is refused anyway.
|
||||
The block for type DS assists in more completely blocking the zone.
|
||||
|
||||
@@UAHL@unbound.conf.local-zone.type@always_nxdomain@@
|
||||
Like :ref:`static<unbound.conf.local-zone.type.static>`, but ignores
|
||||
@@ -3041,6 +3110,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
|
||||
@@ -3223,6 +3304,10 @@ These options are part of the ``server:`` section.
|
||||
Hard limit on the number of times Unbound is allowed to restart a query
|
||||
upon encountering a CNAME record.
|
||||
Results in SERVFAIL when reached.
|
||||
This applies to chained CNAME records but not sporadic CNAME records that
|
||||
could be encountered in the lifetime of the query's resolution effort.
|
||||
When a CNAME chain concludes, the counter keeping track of this limit is
|
||||
reset.
|
||||
Changing this value needs caution as it can allow long CNAME chains to be
|
||||
accepted, where Unbound needs to verify (resolve) each link individually.
|
||||
|
||||
@@ -3247,6 +3332,15 @@ These options are part of the ``server:`` section.
|
||||
Default: 11
|
||||
|
||||
|
||||
@@UAHL@unbound.conf@iter-scrub-rrsig@@: *<number>*
|
||||
Limit on the number of RRSIGs allowed for an RRset, from the iterator
|
||||
scrubber.
|
||||
This protects against an overly large number of RRSIGs.
|
||||
Clips off the remainder of the RRSIG list at that point.
|
||||
|
||||
Default: 8
|
||||
|
||||
|
||||
@@UAHL@unbound.conf@max-global-quota@@: *<number>*
|
||||
Limit on the number of upstream queries sent out for an incoming query and
|
||||
its subqueries from recursion.
|
||||
@@ -3411,7 +3505,7 @@ To setup the correct self-signed certificates use the
|
||||
Default: no
|
||||
|
||||
|
||||
@@UAHL@unbound.conf.remote@control-interface@@: *<IP address or interface name or path>*
|
||||
@@UAHL@unbound.conf.remote@control-interface@@: *<IP address or interface name[@port] or path>*
|
||||
Give IPv4 or IPv6 addresses or local socket path to listen on for control
|
||||
commands.
|
||||
If an interface name is used instead of an IP address, the list of IP
|
||||
@@ -3961,6 +4055,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
|
||||
@@ -4161,6 +4280,17 @@ servers.
|
||||
Use a specific NAT64 prefix to reach IPv4-only servers.
|
||||
The prefix length must be one of /32, /40, /48, /56, /64 or /96.
|
||||
|
||||
The NAT64 prefix is allowed by the
|
||||
:ref:`do-not-query-address<unbound.conf.do-not-query-address>` option,
|
||||
so that there is a clear outcome of addresses in both; the NAT64 prefix
|
||||
is allowed.
|
||||
The IPv4 address could be filtered by the
|
||||
:ref:`do-not-query-address<unbound.conf.do-not-query-address>` option,
|
||||
if needed.
|
||||
Allowing the NAT64 prefix is useful when using do-not-query-address
|
||||
for a cluster of machines that is IPv6-only and uses NAT64, but does
|
||||
not have internet access.
|
||||
|
||||
Default: 64:ff9b::/96 (same as :ref:`dns64-prefix<unbound.conf.dns64.dns64-prefix>`)
|
||||
|
||||
.. _unbound.conf.dnscrypt:
|
||||
@@ -5030,6 +5160,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>`.
|
||||
@@ -5130,6 +5264,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
|
||||
----------------------
|
||||
|
||||
|
||||
@@ -1007,7 +1007,6 @@ EXCLUDE = ./build \
|
||||
libunbound/python/doc \
|
||||
libunbound/python/examples \
|
||||
./ldns-src \
|
||||
./simdzone \
|
||||
README.md \
|
||||
doc/control_proto_spec.txt \
|
||||
doc/requirements.txt
|
||||
|
||||
@@ -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);
|
||||
|
||||
+92
-3
@@ -70,6 +70,7 @@ subnet_data_delete(void *d, void *ATTR_UNUSED(arg))
|
||||
r = (struct subnet_msg_cache_data*)d;
|
||||
addrtree_delete(r->tree4);
|
||||
addrtree_delete(r->tree6);
|
||||
free(r->reason_fail);
|
||||
free(r);
|
||||
}
|
||||
|
||||
@@ -84,6 +85,8 @@ msg_cache_sizefunc(void *k, void *d)
|
||||
+ q->key.qname_len + lock_get_mem(&q->entry.lock);
|
||||
s += addrtree_size(r->tree4);
|
||||
s += addrtree_size(r->tree6);
|
||||
if(r->reason_fail)
|
||||
s += strlen(r->reason_fail)+1;
|
||||
return s;
|
||||
}
|
||||
|
||||
@@ -200,12 +203,18 @@ int ecs_whitelist_check(struct query_info* qinfo,
|
||||
if(sq->ecs_server_out.subnet_source_mask == 0) {
|
||||
sq->subnet_sent_no_subnet = 1;
|
||||
sq->subnet_sent = 0;
|
||||
/* The result should end up in subnet cache,
|
||||
* not in global cache. */
|
||||
qstate->no_cache_store = 1;
|
||||
return 1;
|
||||
}
|
||||
subnet_ecs_opt_list_append(&sq->ecs_server_out,
|
||||
&qstate->edns_opts_back_out, qstate, region);
|
||||
}
|
||||
sq->subnet_sent = 1;
|
||||
/* Do not store servfails in global cache, since the subnet
|
||||
* option is sent out. */
|
||||
qstate->no_cache_store = 1;
|
||||
}
|
||||
else {
|
||||
/* Outgoing ECS option is set, but we don't want to sent it to
|
||||
@@ -427,6 +436,35 @@ update_cache(struct module_qstate *qstate, int id)
|
||||
}
|
||||
/* lru_entry->lock is locked regardless of how we got here,
|
||||
* either from the slabhash_lookup, or above in the new allocated */
|
||||
if(!qstate->return_msg && qstate->error_response_cache) {
|
||||
struct subnet_msg_cache_data *data =
|
||||
(struct subnet_msg_cache_data*)lru_entry->data;
|
||||
data->ttl_servfail = *qstate->env->now + NORR_TTL;
|
||||
data->ede_fail = errinf_to_reason_bogus(qstate);
|
||||
diff_size = (data->reason_fail?strlen(data->reason_fail)+1:0);
|
||||
if(qstate->errinf) {
|
||||
char* str = errinf_to_str_misc(qstate);
|
||||
free(data->reason_fail);
|
||||
data->reason_fail = NULL;
|
||||
if(str)
|
||||
data->reason_fail = strdup(str);
|
||||
}
|
||||
diff_size = (data->reason_fail?strlen(data->reason_fail)+1:0)
|
||||
- diff_size;
|
||||
lock_rw_unlock(&lru_entry->lock);
|
||||
if (need_to_insert) {
|
||||
slabhash_insert(subnet_msg_cache, h, lru_entry,
|
||||
lru_entry->data, NULL);
|
||||
} else {
|
||||
slabhash_update_space_used(subnet_msg_cache, h, NULL,
|
||||
diff_size);
|
||||
}
|
||||
return;
|
||||
}
|
||||
if(!qstate->return_msg) {
|
||||
lock_rw_unlock(&lru_entry->lock);
|
||||
return;
|
||||
}
|
||||
/* Step 2, find the correct tree */
|
||||
if (!(tree = get_tree(lru_entry->data, edns, sne, qstate->env->cfg))) {
|
||||
lock_rw_unlock(&lru_entry->lock);
|
||||
@@ -470,6 +508,21 @@ update_cache(struct module_qstate *qstate, int id)
|
||||
}
|
||||
}
|
||||
|
||||
/** See if there is a stored servfail, returns true if so, and sets reply. */
|
||||
static int
|
||||
lookup_check_servfail(struct module_qstate *qstate,
|
||||
struct subnet_msg_cache_data *data)
|
||||
{
|
||||
struct module_env *env = qstate->env;
|
||||
if(!data)
|
||||
return 0;
|
||||
if(!data->ttl_servfail || TTL_IS_EXPIRED(data->ttl_servfail, *env->now))
|
||||
return 0;
|
||||
qstate->return_rcode = LDNS_RCODE_SERVFAIL;
|
||||
errinf_ede(qstate, data->reason_fail, data->ede_fail);
|
||||
return 1;
|
||||
}
|
||||
|
||||
/** Lookup in cache and reply true iff reply is sent. */
|
||||
static int
|
||||
lookup_and_reply(struct module_qstate *qstate, int id, struct subnet_qstate *sq, int prefetch)
|
||||
@@ -483,6 +536,8 @@ lookup_and_reply(struct module_qstate *qstate, int id, struct subnet_qstate *sq,
|
||||
struct addrtree *tree;
|
||||
struct addrnode *node;
|
||||
uint8_t scope;
|
||||
int must_validate = (!(qstate->query_flags&BIT_CD)
|
||||
|| qstate->env->cfg->ignore_cd) && qstate->env->need_to_validate;
|
||||
|
||||
memset(&sq->ecs_client_out, 0, sizeof(sq->ecs_client_out));
|
||||
|
||||
@@ -496,12 +551,20 @@ lookup_and_reply(struct module_qstate *qstate, int id, struct subnet_qstate *sq,
|
||||
tree = (ecs->subnet_addr_fam == EDNSSUBNET_ADDRFAM_IP4)?
|
||||
data->tree4 : data->tree6;
|
||||
if (!tree) { /* qinfo in cache but not for this family */
|
||||
if(lookup_check_servfail(qstate, data)) {
|
||||
lock_rw_unlock(&e->lock);
|
||||
return 1;
|
||||
}
|
||||
lock_rw_unlock(&e->lock);
|
||||
return 0;
|
||||
}
|
||||
node = addrtree_find(tree, (addrkey_t*)ecs->subnet_addr,
|
||||
ecs->subnet_source_mask, *env->now);
|
||||
if (!node) { /* plain old cache miss */
|
||||
if(lookup_check_servfail(qstate, data)) {
|
||||
lock_rw_unlock(&e->lock);
|
||||
return 1;
|
||||
}
|
||||
lock_rw_unlock(&e->lock);
|
||||
return 0;
|
||||
}
|
||||
@@ -510,12 +573,24 @@ lookup_and_reply(struct module_qstate *qstate, int id, struct subnet_qstate *sq,
|
||||
(struct reply_info *)node->elem, qstate->region, *env->now, 0,
|
||||
env->scratch);
|
||||
scope = (uint8_t)node->scope;
|
||||
lock_rw_unlock(&e->lock);
|
||||
|
||||
if (!qstate->return_msg) { /* Failed allocation or expired TTL */
|
||||
if(lookup_check_servfail(qstate, data)) {
|
||||
lock_rw_unlock(&e->lock);
|
||||
return 1;
|
||||
}
|
||||
lock_rw_unlock(&e->lock);
|
||||
return 0;
|
||||
}
|
||||
|
||||
lock_rw_unlock(&e->lock);
|
||||
if(qstate->return_msg->rep->security == sec_status_unchecked
|
||||
&& must_validate) {
|
||||
/* The message has to be validated first. */
|
||||
verbose(VERB_ALGO, "subnet: unchecked cache entry needs "
|
||||
"validation");
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (sq->subnet_downstream) { /* relay to interested client */
|
||||
sq->ecs_client_out.subnet_scope_mask = scope;
|
||||
sq->ecs_client_out.subnet_addr_fam = ecs->subnet_addr_fam;
|
||||
@@ -570,7 +645,10 @@ generate_sub_request(struct module_qstate *qstate, int id, struct subnet_qstate*
|
||||
qflags |= BIT_RD;
|
||||
if((qstate->query_flags & BIT_CD)!=0) {
|
||||
qflags |= BIT_CD;
|
||||
valrec = 1;
|
||||
/* The valrec is left off. Leave out: valrec = 1;
|
||||
* So that the cache is protected with DNSSEC validation.
|
||||
* Just like the global cache. DNSSEC validation is performed
|
||||
* regardless of the setting of the querier's CD flag. */
|
||||
}
|
||||
|
||||
fptr_ok(fptr_whitelist_modenv_attach_sub(qstate->env->attach_sub));
|
||||
@@ -640,6 +718,12 @@ eval_response(struct module_qstate *qstate, int id, struct subnet_qstate *sq)
|
||||
/* already an answer and its not a message, but retain
|
||||
* the actual rcode, instead of module_error, so send
|
||||
* module_finished */
|
||||
if(qstate->error_response_cache) {
|
||||
verbose(VERB_ALGO, "subnet: store error response");
|
||||
lock_rw_wrlock(&sne->biglock);
|
||||
update_cache(qstate, id);
|
||||
lock_rw_unlock(&sne->biglock);
|
||||
}
|
||||
return module_finished;
|
||||
}
|
||||
|
||||
@@ -889,9 +973,11 @@ ecs_edns_back_parsed(struct module_qstate* qstate, int id,
|
||||
sq->max_scope = sq->ecs_server_in.subnet_scope_mask;
|
||||
} else if(sq->subnet_sent_no_subnet) {
|
||||
/* The answer can be stored as scope 0, not in global cache. */
|
||||
/* This was already set in ecs_whitelist_check */
|
||||
qstate->no_cache_store = 1;
|
||||
} else if(sq->subnet_sent) {
|
||||
/* Need another query to be able to store in global cache. */
|
||||
/* This was already set in ecs_whitelist_check */
|
||||
qstate->no_cache_store = 1;
|
||||
}
|
||||
|
||||
@@ -929,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;
|
||||
@@ -1008,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;
|
||||
|
||||
@@ -1079,6 +1167,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;
|
||||
if(verbosity >= VERB_ALGO) {
|
||||
subnet_log_print("reply has edns subnet",
|
||||
edns_opt_list_find(
|
||||
|
||||
@@ -69,8 +69,18 @@ struct subnet_env {
|
||||
};
|
||||
|
||||
struct subnet_msg_cache_data {
|
||||
/** Tree for nodes with IPv4 subnets. */
|
||||
struct addrtree* tree4;
|
||||
/** Tree for nodes with IPv6 subnets. */
|
||||
struct addrtree* tree6;
|
||||
/** If servfail is stored, for how long. Abs time in seconds.
|
||||
* This protects against too much recusion on the item when
|
||||
* resolution fails, for a couple of seconds. */
|
||||
time_t ttl_servfail;
|
||||
/** servfail ede */
|
||||
sldns_ede_code ede_fail;
|
||||
/** servfail reason */
|
||||
char* reason_fail;
|
||||
};
|
||||
|
||||
struct subnet_qstate {
|
||||
|
||||
Executable
+501
@@ -0,0 +1,501 @@
|
||||
#!/usr/bin/sh
|
||||
# install - install a program, script, or datafile
|
||||
|
||||
scriptversion=2013-12-25.23; # UTC
|
||||
|
||||
# This originates from X11R5 (mit/util/scripts/install.sh), which was
|
||||
# later released in X11R6 (xc/config/util/install.sh) with the
|
||||
# following copyright and license.
|
||||
#
|
||||
# Copyright (C) 1994 X Consortium
|
||||
#
|
||||
# Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
# of this software and associated documentation files (the "Software"), to
|
||||
# deal in the Software without restriction, including without limitation the
|
||||
# rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
|
||||
# sell copies of the Software, and to permit persons to whom the Software is
|
||||
# furnished to do so, subject to the following conditions:
|
||||
#
|
||||
# The above copyright notice and this permission notice shall be included in
|
||||
# all copies or substantial portions of the Software.
|
||||
#
|
||||
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
# X CONSORTIUM BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
|
||||
# AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNEC-
|
||||
# TION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
#
|
||||
# Except as contained in this notice, the name of the X Consortium shall not
|
||||
# be used in advertising or otherwise to promote the sale, use or other deal-
|
||||
# ings in this Software without prior written authorization from the X Consor-
|
||||
# tium.
|
||||
#
|
||||
#
|
||||
# FSF changes to this file are in the public domain.
|
||||
#
|
||||
# Calling this script install-sh is preferred over install.sh, to prevent
|
||||
# 'make' implicit rules from creating a file called install from it
|
||||
# when there is no Makefile.
|
||||
#
|
||||
# This script is compatible with the BSD install script, but was written
|
||||
# from scratch.
|
||||
|
||||
tab=' '
|
||||
nl='
|
||||
'
|
||||
IFS=" $tab$nl"
|
||||
|
||||
# Set DOITPROG to "echo" to test this script.
|
||||
|
||||
doit=${DOITPROG-}
|
||||
doit_exec=${doit:-exec}
|
||||
|
||||
# Put in absolute file names if you don't have them in your path;
|
||||
# or use environment vars.
|
||||
|
||||
chgrpprog=${CHGRPPROG-chgrp}
|
||||
chmodprog=${CHMODPROG-chmod}
|
||||
chownprog=${CHOWNPROG-chown}
|
||||
cmpprog=${CMPPROG-cmp}
|
||||
cpprog=${CPPROG-cp}
|
||||
mkdirprog=${MKDIRPROG-mkdir}
|
||||
mvprog=${MVPROG-mv}
|
||||
rmprog=${RMPROG-rm}
|
||||
stripprog=${STRIPPROG-strip}
|
||||
|
||||
posix_mkdir=
|
||||
|
||||
# Desired mode of installed file.
|
||||
mode=0755
|
||||
|
||||
chgrpcmd=
|
||||
chmodcmd=$chmodprog
|
||||
chowncmd=
|
||||
mvcmd=$mvprog
|
||||
rmcmd="$rmprog -f"
|
||||
stripcmd=
|
||||
|
||||
src=
|
||||
dst=
|
||||
dir_arg=
|
||||
dst_arg=
|
||||
|
||||
copy_on_change=false
|
||||
is_target_a_directory=possibly
|
||||
|
||||
usage="\
|
||||
Usage: $0 [OPTION]... [-T] SRCFILE DSTFILE
|
||||
or: $0 [OPTION]... SRCFILES... DIRECTORY
|
||||
or: $0 [OPTION]... -t DIRECTORY SRCFILES...
|
||||
or: $0 [OPTION]... -d DIRECTORIES...
|
||||
|
||||
In the 1st form, copy SRCFILE to DSTFILE.
|
||||
In the 2nd and 3rd, copy all SRCFILES to DIRECTORY.
|
||||
In the 4th, create DIRECTORIES.
|
||||
|
||||
Options:
|
||||
--help display this help and exit.
|
||||
--version display version info and exit.
|
||||
|
||||
-c (ignored)
|
||||
-C install only if different (preserve the last data modification time)
|
||||
-d create directories instead of installing files.
|
||||
-g GROUP $chgrpprog installed files to GROUP.
|
||||
-m MODE $chmodprog installed files to MODE.
|
||||
-o USER $chownprog installed files to USER.
|
||||
-s $stripprog installed files.
|
||||
-t DIRECTORY install into DIRECTORY.
|
||||
-T report an error if DSTFILE is a directory.
|
||||
|
||||
Environment variables override the default commands:
|
||||
CHGRPPROG CHMODPROG CHOWNPROG CMPPROG CPPROG MKDIRPROG MVPROG
|
||||
RMPROG STRIPPROG
|
||||
"
|
||||
|
||||
while test $# -ne 0; do
|
||||
case $1 in
|
||||
-c) ;;
|
||||
|
||||
-C) copy_on_change=true;;
|
||||
|
||||
-d) dir_arg=true;;
|
||||
|
||||
-g) chgrpcmd="$chgrpprog $2"
|
||||
shift;;
|
||||
|
||||
--help) echo "$usage"; exit $?;;
|
||||
|
||||
-m) mode=$2
|
||||
case $mode in
|
||||
*' '* | *"$tab"* | *"$nl"* | *'*'* | *'?'* | *'['*)
|
||||
echo "$0: invalid mode: $mode" >&2
|
||||
exit 1;;
|
||||
esac
|
||||
shift;;
|
||||
|
||||
-o) chowncmd="$chownprog $2"
|
||||
shift;;
|
||||
|
||||
-s) stripcmd=$stripprog;;
|
||||
|
||||
-t)
|
||||
is_target_a_directory=always
|
||||
dst_arg=$2
|
||||
# Protect names problematic for 'test' and other utilities.
|
||||
case $dst_arg in
|
||||
-* | [=\(\)!]) dst_arg=./$dst_arg;;
|
||||
esac
|
||||
shift;;
|
||||
|
||||
-T) is_target_a_directory=never;;
|
||||
|
||||
--version) echo "$0 $scriptversion"; exit $?;;
|
||||
|
||||
--) shift
|
||||
break;;
|
||||
|
||||
-*) echo "$0: invalid option: $1" >&2
|
||||
exit 1;;
|
||||
|
||||
*) break;;
|
||||
esac
|
||||
shift
|
||||
done
|
||||
|
||||
# We allow the use of options -d and -T together, by making -d
|
||||
# take the precedence; this is for compatibility with GNU install.
|
||||
|
||||
if test -n "$dir_arg"; then
|
||||
if test -n "$dst_arg"; then
|
||||
echo "$0: target directory not allowed when installing a directory." >&2
|
||||
exit 1
|
||||
fi
|
||||
fi
|
||||
|
||||
if test $# -ne 0 && test -z "$dir_arg$dst_arg"; then
|
||||
# When -d is used, all remaining arguments are directories to create.
|
||||
# When -t is used, the destination is already specified.
|
||||
# Otherwise, the last argument is the destination. Remove it from $@.
|
||||
for arg
|
||||
do
|
||||
if test -n "$dst_arg"; then
|
||||
# $@ is not empty: it contains at least $arg.
|
||||
set fnord "$@" "$dst_arg"
|
||||
shift # fnord
|
||||
fi
|
||||
shift # arg
|
||||
dst_arg=$arg
|
||||
# Protect names problematic for 'test' and other utilities.
|
||||
case $dst_arg in
|
||||
-* | [=\(\)!]) dst_arg=./$dst_arg;;
|
||||
esac
|
||||
done
|
||||
fi
|
||||
|
||||
if test $# -eq 0; then
|
||||
if test -z "$dir_arg"; then
|
||||
echo "$0: no input file specified." >&2
|
||||
exit 1
|
||||
fi
|
||||
# It's OK to call 'install-sh -d' without argument.
|
||||
# This can happen when creating conditional directories.
|
||||
exit 0
|
||||
fi
|
||||
|
||||
if test -z "$dir_arg"; then
|
||||
if test $# -gt 1 || test "$is_target_a_directory" = always; then
|
||||
if test ! -d "$dst_arg"; then
|
||||
echo "$0: $dst_arg: Is not a directory." >&2
|
||||
exit 1
|
||||
fi
|
||||
fi
|
||||
fi
|
||||
|
||||
if test -z "$dir_arg"; then
|
||||
do_exit='(exit $ret); exit $ret'
|
||||
trap "ret=129; $do_exit" 1
|
||||
trap "ret=130; $do_exit" 2
|
||||
trap "ret=141; $do_exit" 13
|
||||
trap "ret=143; $do_exit" 15
|
||||
|
||||
# Set umask so as not to create temps with too-generous modes.
|
||||
# However, 'strip' requires both read and write access to temps.
|
||||
case $mode in
|
||||
# Optimize common cases.
|
||||
*644) cp_umask=133;;
|
||||
*755) cp_umask=22;;
|
||||
|
||||
*[0-7])
|
||||
if test -z "$stripcmd"; then
|
||||
u_plus_rw=
|
||||
else
|
||||
u_plus_rw='% 200'
|
||||
fi
|
||||
cp_umask=`expr '(' 777 - $mode % 1000 ')' $u_plus_rw`;;
|
||||
*)
|
||||
if test -z "$stripcmd"; then
|
||||
u_plus_rw=
|
||||
else
|
||||
u_plus_rw=,u+rw
|
||||
fi
|
||||
cp_umask=$mode$u_plus_rw;;
|
||||
esac
|
||||
fi
|
||||
|
||||
for src
|
||||
do
|
||||
# Protect names problematic for 'test' and other utilities.
|
||||
case $src in
|
||||
-* | [=\(\)!]) src=./$src;;
|
||||
esac
|
||||
|
||||
if test -n "$dir_arg"; then
|
||||
dst=$src
|
||||
dstdir=$dst
|
||||
test -d "$dstdir"
|
||||
dstdir_status=$?
|
||||
else
|
||||
|
||||
# Waiting for this to be detected by the "$cpprog $src $dsttmp" command
|
||||
# might cause directories to be created, which would be especially bad
|
||||
# if $src (and thus $dsttmp) contains '*'.
|
||||
if test ! -f "$src" && test ! -d "$src"; then
|
||||
echo "$0: $src does not exist." >&2
|
||||
exit 1
|
||||
fi
|
||||
|
||||
if test -z "$dst_arg"; then
|
||||
echo "$0: no destination specified." >&2
|
||||
exit 1
|
||||
fi
|
||||
dst=$dst_arg
|
||||
|
||||
# If destination is a directory, append the input filename; won't work
|
||||
# if double slashes aren't ignored.
|
||||
if test -d "$dst"; then
|
||||
if test "$is_target_a_directory" = never; then
|
||||
echo "$0: $dst_arg: Is a directory" >&2
|
||||
exit 1
|
||||
fi
|
||||
dstdir=$dst
|
||||
dst=$dstdir/`basename "$src"`
|
||||
dstdir_status=0
|
||||
else
|
||||
dstdir=`dirname "$dst"`
|
||||
test -d "$dstdir"
|
||||
dstdir_status=$?
|
||||
fi
|
||||
fi
|
||||
|
||||
obsolete_mkdir_used=false
|
||||
|
||||
if test $dstdir_status != 0; then
|
||||
case $posix_mkdir in
|
||||
'')
|
||||
# Create intermediate dirs using mode 755 as modified by the umask.
|
||||
# This is like FreeBSD 'install' as of 1997-10-28.
|
||||
umask=`umask`
|
||||
case $stripcmd.$umask in
|
||||
# Optimize common cases.
|
||||
*[2367][2367]) mkdir_umask=$umask;;
|
||||
.*0[02][02] | .[02][02] | .[02]) mkdir_umask=22;;
|
||||
|
||||
*[0-7])
|
||||
mkdir_umask=`expr $umask + 22 \
|
||||
- $umask % 100 % 40 + $umask % 20 \
|
||||
- $umask % 10 % 4 + $umask % 2
|
||||
`;;
|
||||
*) mkdir_umask=$umask,go-w;;
|
||||
esac
|
||||
|
||||
# With -d, create the new directory with the user-specified mode.
|
||||
# Otherwise, rely on $mkdir_umask.
|
||||
if test -n "$dir_arg"; then
|
||||
mkdir_mode=-m$mode
|
||||
else
|
||||
mkdir_mode=
|
||||
fi
|
||||
|
||||
posix_mkdir=false
|
||||
case $umask in
|
||||
*[123567][0-7][0-7])
|
||||
# POSIX mkdir -p sets u+wx bits regardless of umask, which
|
||||
# is incompatible with FreeBSD 'install' when (umask & 300) != 0.
|
||||
;;
|
||||
*)
|
||||
tmpdir=${TMPDIR-/tmp}/ins$RANDOM-$$
|
||||
trap 'ret=$?; rmdir "$tmpdir/d" "$tmpdir" 2>/dev/null; exit $ret' 0
|
||||
|
||||
if (umask $mkdir_umask &&
|
||||
exec $mkdirprog $mkdir_mode -p -- "$tmpdir/d") >/dev/null 2>&1
|
||||
then
|
||||
if test -z "$dir_arg" || {
|
||||
# Check for POSIX incompatibilities with -m.
|
||||
# HP-UX 11.23 and IRIX 6.5 mkdir -m -p sets group- or
|
||||
# other-writable bit of parent directory when it shouldn't.
|
||||
# FreeBSD 6.1 mkdir -m -p sets mode of existing directory.
|
||||
ls_ld_tmpdir=`ls -ld "$tmpdir"`
|
||||
case $ls_ld_tmpdir in
|
||||
d????-?r-*) different_mode=700;;
|
||||
d????-?--*) different_mode=755;;
|
||||
*) false;;
|
||||
esac &&
|
||||
$mkdirprog -m$different_mode -p -- "$tmpdir" && {
|
||||
ls_ld_tmpdir_1=`ls -ld "$tmpdir"`
|
||||
test "$ls_ld_tmpdir" = "$ls_ld_tmpdir_1"
|
||||
}
|
||||
}
|
||||
then posix_mkdir=:
|
||||
fi
|
||||
rmdir "$tmpdir/d" "$tmpdir"
|
||||
else
|
||||
# Remove any dirs left behind by ancient mkdir implementations.
|
||||
rmdir ./$mkdir_mode ./-p ./-- 2>/dev/null
|
||||
fi
|
||||
trap '' 0;;
|
||||
esac;;
|
||||
esac
|
||||
|
||||
if
|
||||
$posix_mkdir && (
|
||||
umask $mkdir_umask &&
|
||||
$doit_exec $mkdirprog $mkdir_mode -p -- "$dstdir"
|
||||
)
|
||||
then :
|
||||
else
|
||||
|
||||
# The umask is ridiculous, or mkdir does not conform to POSIX,
|
||||
# or it failed possibly due to a race condition. Create the
|
||||
# directory the slow way, step by step, checking for races as we go.
|
||||
|
||||
case $dstdir in
|
||||
/*) prefix='/';;
|
||||
[-=\(\)!]*) prefix='./';;
|
||||
*) prefix='';;
|
||||
esac
|
||||
|
||||
oIFS=$IFS
|
||||
IFS=/
|
||||
set -f
|
||||
set fnord $dstdir
|
||||
shift
|
||||
set +f
|
||||
IFS=$oIFS
|
||||
|
||||
prefixes=
|
||||
|
||||
for d
|
||||
do
|
||||
test X"$d" = X && continue
|
||||
|
||||
prefix=$prefix$d
|
||||
if test -d "$prefix"; then
|
||||
prefixes=
|
||||
else
|
||||
if $posix_mkdir; then
|
||||
(umask=$mkdir_umask &&
|
||||
$doit_exec $mkdirprog $mkdir_mode -p -- "$dstdir") && break
|
||||
# Don't fail if two instances are running concurrently.
|
||||
test -d "$prefix" || exit 1
|
||||
else
|
||||
case $prefix in
|
||||
*\'*) qprefix=`echo "$prefix" | sed "s/'/'\\\\\\\\''/g"`;;
|
||||
*) qprefix=$prefix;;
|
||||
esac
|
||||
prefixes="$prefixes '$qprefix'"
|
||||
fi
|
||||
fi
|
||||
prefix=$prefix/
|
||||
done
|
||||
|
||||
if test -n "$prefixes"; then
|
||||
# Don't fail if two instances are running concurrently.
|
||||
(umask $mkdir_umask &&
|
||||
eval "\$doit_exec \$mkdirprog $prefixes") ||
|
||||
test -d "$dstdir" || exit 1
|
||||
obsolete_mkdir_used=true
|
||||
fi
|
||||
fi
|
||||
fi
|
||||
|
||||
if test -n "$dir_arg"; then
|
||||
{ test -z "$chowncmd" || $doit $chowncmd "$dst"; } &&
|
||||
{ test -z "$chgrpcmd" || $doit $chgrpcmd "$dst"; } &&
|
||||
{ test "$obsolete_mkdir_used$chowncmd$chgrpcmd" = false ||
|
||||
test -z "$chmodcmd" || $doit $chmodcmd $mode "$dst"; } || exit 1
|
||||
else
|
||||
|
||||
# Make a couple of temp file names in the proper directory.
|
||||
dsttmp=$dstdir/_inst.$$_
|
||||
rmtmp=$dstdir/_rm.$$_
|
||||
|
||||
# Trap to clean up those temp files at exit.
|
||||
trap 'ret=$?; rm -f "$dsttmp" "$rmtmp" && exit $ret' 0
|
||||
|
||||
# Copy the file name to the temp name.
|
||||
(umask $cp_umask && $doit_exec $cpprog "$src" "$dsttmp") &&
|
||||
|
||||
# and set any options; do chmod last to preserve setuid bits.
|
||||
#
|
||||
# If any of these fail, we abort the whole thing. If we want to
|
||||
# ignore errors from any of these, just make sure not to ignore
|
||||
# errors from the above "$doit $cpprog $src $dsttmp" command.
|
||||
#
|
||||
{ test -z "$chowncmd" || $doit $chowncmd "$dsttmp"; } &&
|
||||
{ test -z "$chgrpcmd" || $doit $chgrpcmd "$dsttmp"; } &&
|
||||
{ test -z "$stripcmd" || $doit $stripcmd "$dsttmp"; } &&
|
||||
{ test -z "$chmodcmd" || $doit $chmodcmd $mode "$dsttmp"; } &&
|
||||
|
||||
# If -C, don't bother to copy if it wouldn't change the file.
|
||||
if $copy_on_change &&
|
||||
old=`LC_ALL=C ls -dlL "$dst" 2>/dev/null` &&
|
||||
new=`LC_ALL=C ls -dlL "$dsttmp" 2>/dev/null` &&
|
||||
set -f &&
|
||||
set X $old && old=:$2:$4:$5:$6 &&
|
||||
set X $new && new=:$2:$4:$5:$6 &&
|
||||
set +f &&
|
||||
test "$old" = "$new" &&
|
||||
$cmpprog "$dst" "$dsttmp" >/dev/null 2>&1
|
||||
then
|
||||
rm -f "$dsttmp"
|
||||
else
|
||||
# Rename the file to the real destination.
|
||||
$doit $mvcmd -f "$dsttmp" "$dst" 2>/dev/null ||
|
||||
|
||||
# The rename failed, perhaps because mv can't rename something else
|
||||
# to itself, or perhaps because mv is so ancient that it does not
|
||||
# support -f.
|
||||
{
|
||||
# Now remove or move aside any old file at destination location.
|
||||
# We try this two ways since rm can't unlink itself on some
|
||||
# systems and the destination file might be busy for other
|
||||
# reasons. In this case, the final cleanup might fail but the new
|
||||
# file should still install successfully.
|
||||
{
|
||||
test ! -f "$dst" ||
|
||||
$doit $rmcmd -f "$dst" 2>/dev/null ||
|
||||
{ $doit $mvcmd -f "$dst" "$rmtmp" 2>/dev/null &&
|
||||
{ $doit $rmcmd -f "$rmtmp" 2>/dev/null; :; }
|
||||
} ||
|
||||
{ echo "$0: cannot unlink or rename $dst" >&2
|
||||
(exit 1); exit 1
|
||||
}
|
||||
} &&
|
||||
|
||||
# Now rename the file to the real destination.
|
||||
$doit $mvcmd "$dsttmp" "$dst"
|
||||
}
|
||||
fi || exit 1
|
||||
|
||||
trap '' 0
|
||||
fi
|
||||
done
|
||||
|
||||
# Local variables:
|
||||
# eval: (add-hook 'write-file-hooks 'time-stamp)
|
||||
# time-stamp-start: "scriptversion="
|
||||
# time-stamp-format: "%:y-%02m-%02d.%02H"
|
||||
# time-stamp-time-zone: "UTC"
|
||||
# time-stamp-end: "; # UTC"
|
||||
# End:
|
||||
@@ -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);
|
||||
|
||||
+167
-1
@@ -207,6 +207,168 @@ size_t priv_get_mem(struct iter_priv* priv)
|
||||
return sizeof(*priv) + regional_get_mem(priv->region);
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if svcparam ipv4hint contains a private address.
|
||||
* @param priv: private address lookup struct.
|
||||
* @param d: the data bytes.
|
||||
* @param data_len: number of data bytes in the svcparam.
|
||||
* @param addr: address to return the private address to log in to.
|
||||
* It has space for IPv4 and IPv6 addresses.
|
||||
* @param addrlen: length of the addr. Returns the correct size for the addr.
|
||||
* @return true if the rdata contains a private address.
|
||||
*/
|
||||
static int svcb_ipv4hint_contains_priv_addr(struct iter_priv* priv,
|
||||
uint8_t* d, uint16_t data_len, struct sockaddr_storage* addr,
|
||||
socklen_t* addrlen)
|
||||
{
|
||||
struct sockaddr_in sa;
|
||||
*addrlen = (socklen_t)sizeof(struct sockaddr_in);
|
||||
memset(&sa, 0, sizeof(struct sockaddr_in));
|
||||
sa.sin_family = AF_INET;
|
||||
sa.sin_port = (in_port_t)htons(UNBOUND_DNS_PORT);
|
||||
|
||||
while(data_len >= LDNS_IP4ADDRLEN) {
|
||||
memmove(&sa.sin_addr, d, LDNS_IP4ADDRLEN);
|
||||
memmove(addr, &sa, *addrlen);
|
||||
if(priv_lookup_addr(priv, addr, *addrlen))
|
||||
return 1;
|
||||
|
||||
d += LDNS_IP4ADDRLEN;
|
||||
data_len -= LDNS_IP4ADDRLEN;
|
||||
}
|
||||
/* if data_len != 0 here, then the svcparam is malformed. */
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if svcparam ipv6hint contains a private address.
|
||||
* @param priv: private address lookup struct.
|
||||
* @param d: the data bytes.
|
||||
* @param data_len: number of data bytes in the svcparam.
|
||||
* @param addr: address to return the private address to log in to.
|
||||
* It has space for IPv4 and IPv6 addresses.
|
||||
* @param addrlen: length of the addr. Returns the correct size for the addr.
|
||||
* @return true if the rdata contains a private address.
|
||||
*/
|
||||
static int svcb_ipv6hint_contains_priv_addr(struct iter_priv* priv,
|
||||
uint8_t* d, uint16_t data_len, struct sockaddr_storage* addr,
|
||||
socklen_t* addrlen)
|
||||
{
|
||||
struct sockaddr_in6 sa;
|
||||
*addrlen = (socklen_t)sizeof(struct sockaddr_in6);
|
||||
memset(&sa, 0, sizeof(struct sockaddr_in6));
|
||||
sa.sin6_family = AF_INET6;
|
||||
sa.sin6_port = (in_port_t)htons(UNBOUND_DNS_PORT);
|
||||
|
||||
while(data_len >= LDNS_IP6ADDRLEN) {
|
||||
memmove(&sa.sin6_addr, d, LDNS_IP6ADDRLEN);
|
||||
memmove(addr, &sa, *addrlen);
|
||||
if(priv_lookup_addr(priv, addr, *addrlen))
|
||||
return 1;
|
||||
|
||||
d += LDNS_IP6ADDRLEN;
|
||||
data_len -= LDNS_IP6ADDRLEN;
|
||||
}
|
||||
/* if data_len != 0 here, then the svcparam is malformed. */
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if type SVCB and HTTPS rdata contains a private address.
|
||||
* @param priv: private address lookup struct.
|
||||
* @param pkt: the packet.
|
||||
* @param rr: the rr with rdata to check.
|
||||
* @param addr: address to return the private address to log in to.
|
||||
* @param addrlen: length of the addr. Initially the total size, on
|
||||
* return the correct size for the addr.
|
||||
* @return true if the rdata contains a private address.
|
||||
*/
|
||||
static int svcb_rr_contains_priv_addr(struct iter_priv* priv,
|
||||
sldns_buffer* pkt, struct rr_parse* rr, struct sockaddr_storage* addr,
|
||||
socklen_t* addrlen)
|
||||
{
|
||||
uint8_t* d = rr->ttl_data;
|
||||
uint16_t svcparamkey, data_len, rdatalen;
|
||||
size_t oldpos, dname_len, dname_start, dname_compr_len;
|
||||
d += 4; /* skip TTL */
|
||||
rdatalen = sldns_read_uint16(d); /* read rdata length */
|
||||
d += 2;
|
||||
|
||||
if(rdatalen < 2 /* priority */ + 1 /* 1 length target */)
|
||||
return 0; /* malformed, too short */
|
||||
d += 2; /* skip priority */
|
||||
rdatalen -= 2;
|
||||
oldpos = sldns_buffer_position(pkt);
|
||||
sldns_buffer_set_position(pkt, (size_t)(d - sldns_buffer_begin(pkt)));
|
||||
dname_start = sldns_buffer_position(pkt);
|
||||
dname_len = pkt_dname_len(pkt);
|
||||
dname_compr_len = sldns_buffer_position(pkt) - dname_start;
|
||||
sldns_buffer_set_position(pkt, oldpos);
|
||||
if(dname_len == 0)
|
||||
return 0; /* dname malformed */
|
||||
if(dname_compr_len > rdatalen)
|
||||
return 0; /* malformed */
|
||||
d += dname_compr_len; /* skip target */
|
||||
rdatalen -= dname_compr_len;
|
||||
|
||||
while(rdatalen >= 4) {
|
||||
svcparamkey = sldns_read_uint16(d);
|
||||
data_len = sldns_read_uint16(d+2);
|
||||
d += 4;
|
||||
rdatalen -= 4;
|
||||
|
||||
/* verify that we have data_len data */
|
||||
if(data_len > rdatalen) {
|
||||
/* It is malformed, but if there are addresses
|
||||
* in there it can be rejected. */
|
||||
data_len = rdatalen;
|
||||
}
|
||||
|
||||
if(!data_len)
|
||||
continue; /* no data for the svcparamkey */
|
||||
|
||||
if(svcparamkey == SVCB_KEY_IPV4HINT) {
|
||||
if(svcb_ipv4hint_contains_priv_addr(priv, d, data_len,
|
||||
addr, addrlen))
|
||||
return 1;
|
||||
} else if(svcparamkey == SVCB_KEY_IPV6HINT) {
|
||||
if(svcb_ipv6hint_contains_priv_addr(priv, d, data_len,
|
||||
addr, addrlen))
|
||||
return 1;
|
||||
}
|
||||
d += data_len;
|
||||
rdatalen -= data_len;
|
||||
}
|
||||
/* If rdatalen != 0 here, then the svcb rdata is malformed. */
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if the SVCB and HTTPS rrset is bad.
|
||||
* @param priv: private address lookup struct.
|
||||
* @param pkt: the packet.
|
||||
* @param rrset: the rrset to check.
|
||||
* @return 1 if the entire rrset has to be removed. 0 if not.
|
||||
* It removes RRs if they have private addresses, and log that.
|
||||
*/
|
||||
static int priv_svcb_rrset_bad(struct iter_priv* priv, sldns_buffer* pkt,
|
||||
struct rrset_parse* rrset)
|
||||
{
|
||||
struct rr_parse* rr, *prev = NULL;
|
||||
struct sockaddr_storage addr;
|
||||
socklen_t addrlen = (socklen_t)sizeof(addr);
|
||||
for(rr = rrset->rr_first; rr; rr = rr->next) {
|
||||
if(svcb_rr_contains_priv_addr(priv, pkt, rr, &addr,
|
||||
&addrlen)) {
|
||||
if(msgparse_rrset_remove_rr("sanitize: removing public name with private address", pkt, rrset, prev, rr, &addr, addrlen))
|
||||
return 1;
|
||||
continue;
|
||||
}
|
||||
prev = rr;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
int priv_rrset_bad(struct iter_priv* priv, sldns_buffer* pkt,
|
||||
struct rrset_parse* rrset)
|
||||
{
|
||||
@@ -268,7 +430,11 @@ int priv_rrset_bad(struct iter_priv* priv, sldns_buffer* pkt,
|
||||
}
|
||||
prev = rr;
|
||||
}
|
||||
}
|
||||
} else if(rrset->type == LDNS_RR_TYPE_SVCB ||
|
||||
rrset->type == LDNS_RR_TYPE_HTTPS) {
|
||||
if(priv_svcb_rrset_bad(priv, pkt, rrset))
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -107,7 +107,7 @@ 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)
|
||||
{
|
||||
uint8_t* origzone = (uint8_t*)"\000"; /* the default */
|
||||
struct ub_packed_rrset_key* s;
|
||||
@@ -122,6 +122,10 @@ 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)
|
||||
@@ -143,6 +147,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) {
|
||||
@@ -249,13 +257,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
|
||||
|
||||
@@ -120,10 +120,14 @@ enum response_type response_type_from_cache(struct dns_msg* msg,
|
||||
* @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.
|
||||
* @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);
|
||||
|
||||
#endif /* ITERATOR_ITER_RESPTYPE_H */
|
||||
|
||||
+143
-11
@@ -285,6 +285,17 @@ synth_cname_rrset(uint8_t** sname, size_t* snamelen, uint8_t* alias,
|
||||
return NULL;
|
||||
memmove(cn->rr_first->ttl_data, rrset->rr_first->ttl_data,
|
||||
sizeof(uint32_t)); /* RFC6672: synth CNAME TTL == DNAME TTL */
|
||||
/* Apply cache TTL policy so DNAME and synthesized CNAME stay equal
|
||||
* and respect cache-min-ttl/cache-max-ttl (same as rdata_copy path). */
|
||||
if(!SERVE_ORIGINAL_TTL) {
|
||||
uint32_t ttl = sldns_read_uint32(cn->rr_first->ttl_data);
|
||||
time_t ttl_t = (time_t)ttl;
|
||||
if(ttl_t < MIN_TTL) ttl_t = MIN_TTL;
|
||||
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);
|
||||
}
|
||||
sldns_write_uint16(cn->rr_first->ttl_data+4, aliaslen);
|
||||
memmove(cn->rr_first->ttl_data+6, alias, aliaslen);
|
||||
cn->rr_first->size = sizeof(uint16_t)+aliaslen;
|
||||
@@ -305,6 +316,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)
|
||||
@@ -383,6 +408,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;
|
||||
@@ -408,6 +435,43 @@ shorten_rrset(sldns_buffer* pkt, struct rrset_parse* rrset, int count)
|
||||
else rrset->rr_first = NULL;
|
||||
}
|
||||
|
||||
/** Shorten RRSIGs list */
|
||||
static void
|
||||
shorten_rrsig(sldns_buffer* pkt, struct rrset_parse* rrset, int count)
|
||||
{
|
||||
/* The too large list of RRSIGs on the RRset is shortened.
|
||||
* This is so that too large content does not overwhelm the cache.
|
||||
* The validator does not validate more than a max number of
|
||||
* RRSIGs as well. */
|
||||
int i;
|
||||
struct rr_parse* rr = rrset->rrsig_first, *prev = NULL;
|
||||
if(!rr)
|
||||
return;
|
||||
for(i=0; i<count; i++) {
|
||||
prev = rr;
|
||||
rr = rr->next;
|
||||
if(!rr)
|
||||
return; /* The RRSIG list is already short. */
|
||||
}
|
||||
if(verbosity >= VERB_QUERY
|
||||
&& rrset->dname_len <= LDNS_MAX_DOMAINLEN) {
|
||||
uint8_t buf[LDNS_MAX_DOMAINLEN+1];
|
||||
dname_pkt_copy(pkt, buf, rrset->dname);
|
||||
log_nametypeclass(VERB_QUERY, "normalize: shorten RRSIGs:",
|
||||
buf, rrset->type, ntohs(rrset->rrset_class));
|
||||
}
|
||||
/* remove further rrsigs */
|
||||
rrset->rrsig_last = prev;
|
||||
rrset->rrsig_count = count;
|
||||
while(rr) {
|
||||
rrset->size -= rr->size;
|
||||
rr = rr->next;
|
||||
}
|
||||
if(rrset->rrsig_last)
|
||||
rrset->rrsig_last->next = NULL;
|
||||
else rrset->rrsig_first = NULL;
|
||||
}
|
||||
|
||||
/**
|
||||
* This routine normalizes a response. This includes removing "irrelevant"
|
||||
* records from the answer and additional sections and (re)synthesizing
|
||||
@@ -430,6 +494,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 &&
|
||||
@@ -445,6 +510,8 @@ scrub_normalize(sldns_buffer* pkt, struct msg_parse* msg,
|
||||
prev = NULL;
|
||||
rrset = msg->rrset_first;
|
||||
while(rrset && rrset->section == LDNS_SECTION_ANSWER) {
|
||||
if((int)rrset->rrsig_count > env->cfg->iter_scrub_rrsig)
|
||||
shorten_rrsig(pkt, rrset, env->cfg->iter_scrub_rrsig);
|
||||
if(cname_length > env->cfg->iter_scrub_cname) {
|
||||
/* Too many CNAMEs, or DNAMEs, from the authority
|
||||
* server, scrub down the length to something
|
||||
@@ -455,8 +522,9 @@ scrub_normalize(sldns_buffer* pkt, struct msg_parse* msg,
|
||||
pkt, msg, prev, &rrset);
|
||||
continue;
|
||||
}
|
||||
if(rrset->type == LDNS_RR_TYPE_DNAME &&
|
||||
pkt_strict_sub(pkt, sname, rrset->dname)) {
|
||||
if(rrset->type == LDNS_RR_TYPE_DNAME &&
|
||||
pkt_strict_sub(pkt, sname, rrset->dname) &&
|
||||
pkt_sub(pkt, rrset->dname, zonename)) {
|
||||
/* check if next rrset is correct CNAME. else,
|
||||
* synthesize a CNAME */
|
||||
struct rrset_parse* nx = rrset->rrset_all_next;
|
||||
@@ -468,6 +536,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 "
|
||||
@@ -502,8 +575,6 @@ scrub_normalize(sldns_buffer* pkt, struct msg_parse* msg,
|
||||
log_err("out of memory synthesizing CNAME");
|
||||
return 0;
|
||||
}
|
||||
/* FIXME: resolve the conflict between synthesized
|
||||
* CNAME ttls and the cache. */
|
||||
rrset = nx;
|
||||
continue;
|
||||
|
||||
@@ -520,12 +591,18 @@ 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 &&
|
||||
nx->type == LDNS_RR_TYPE_DNAME &&
|
||||
nx->rr_count == 1 &&
|
||||
pkt_strict_sub(pkt, sname, nx->dname)) {
|
||||
pkt_strict_sub(pkt, sname, nx->dname) &&
|
||||
pkt_sub(pkt, nx->dname, zonename)) {
|
||||
/* there is a DNAME after this CNAME, it
|
||||
* is in the ANSWER section, and the DNAME
|
||||
* applies to the name we cover */
|
||||
@@ -597,6 +674,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;
|
||||
@@ -620,6 +698,8 @@ scrub_normalize(sldns_buffer* pkt, struct msg_parse* msg,
|
||||
"RRset:", pkt, msg, prev, &rrset);
|
||||
continue;
|
||||
}
|
||||
if((int)rrset->rrsig_count > env->cfg->iter_scrub_rrsig)
|
||||
shorten_rrsig(pkt, rrset, env->cfg->iter_scrub_rrsig);
|
||||
/* only one NS set allowed in authority section */
|
||||
if(rrset->type==LDNS_RR_TYPE_NS) {
|
||||
/* NS set must be pertinent to the query */
|
||||
@@ -680,6 +760,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 {
|
||||
@@ -725,7 +810,13 @@ scrub_normalize(sldns_buffer* pkt, struct msg_parse* msg,
|
||||
rrset->rrset_all_next = NULL;
|
||||
return 1;
|
||||
}
|
||||
mark_additional_rrset(pkt, msg, rrset);
|
||||
/* Only mark glue as allowed for type NS in the authority
|
||||
* section. Other RR types do not get glue for them, it
|
||||
* is allowed from the answer section, but not authority
|
||||
* so that a message can not have address records cached
|
||||
* as a side effect to the query. */
|
||||
if(rrset->type==LDNS_RR_TYPE_NS)
|
||||
mark_additional_rrset(pkt, msg, rrset);
|
||||
prev = rrset;
|
||||
rrset = rrset->rrset_all_next;
|
||||
}
|
||||
@@ -762,6 +853,8 @@ scrub_normalize(sldns_buffer* pkt, struct msg_parse* msg,
|
||||
"RRset:", pkt, msg, prev, &rrset);
|
||||
continue;
|
||||
}
|
||||
if((int)rrset->rrsig_count > env->cfg->iter_scrub_rrsig)
|
||||
shorten_rrsig(pkt, rrset, env->cfg->iter_scrub_rrsig);
|
||||
prev = rrset;
|
||||
rrset = rrset->rrset_all_next;
|
||||
}
|
||||
@@ -908,12 +1001,20 @@ 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 */
|
||||
@@ -972,8 +1073,10 @@ scrub_sanitize(sldns_buffer* pkt, struct msg_parse* msg,
|
||||
}
|
||||
|
||||
/* remove private addresses */
|
||||
if( (rrset->type == LDNS_RR_TYPE_A ||
|
||||
rrset->type == LDNS_RR_TYPE_AAAA)) {
|
||||
if(rrset->type == LDNS_RR_TYPE_A ||
|
||||
rrset->type == LDNS_RR_TYPE_AAAA ||
|
||||
rrset->type == LDNS_RR_TYPE_SVCB ||
|
||||
rrset->type == LDNS_RR_TYPE_HTTPS) {
|
||||
|
||||
/* do not set servfail since this leads to too
|
||||
* many drops of other people using rfc1918 space */
|
||||
@@ -1068,6 +1171,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;
|
||||
}
|
||||
|
||||
@@ -1075,11 +1193,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) )
|
||||
@@ -1104,11 +1226,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 */
|
||||
|
||||
+39
-4
@@ -308,9 +308,30 @@ iter_filter_unsuitable(struct iter_env* iter_env, struct module_env* env,
|
||||
if(a->bogus)
|
||||
return -1; /* address of server is bogus */
|
||||
if(donotq_lookup(iter_env->donotq, &a->addr, a->addrlen)) {
|
||||
log_addr(VERB_ALGO, "skip addr on the donotquery list",
|
||||
&a->addr, a->addrlen);
|
||||
return -1; /* server is on the donotquery list */
|
||||
if(iter_env->nat64.use_nat64 &&
|
||||
addr_is_ip6(&a->addr, a->addrlen) &&
|
||||
a->addrlen == iter_env->nat64.nat64_prefix_addrlen &&
|
||||
addr_in_common(&a->addr, 128,
|
||||
&iter_env->nat64.nat64_prefix_addr,
|
||||
iter_env->nat64.nat64_prefix_net,
|
||||
iter_env->nat64.nat64_prefix_addrlen) ==
|
||||
iter_env->nat64.nat64_prefix_net) {
|
||||
/* The NAT64 is enabled, and address is IPv6, it is
|
||||
* in the NAT64 prefix. It is allowed.
|
||||
* So that in an IPv6-only cluster without internet
|
||||
* access, that makes the NAT64 translation continue
|
||||
* to work. The NAT64 prefix is allowed. */
|
||||
/* Otherwise, after a timeout, the already NAT64
|
||||
* translated address would be treated differently,
|
||||
* and that causes confusion. */
|
||||
log_addr(VERB_ALGO, "the addr is on the donotquery "
|
||||
"list, but allowed because it is NAT64",
|
||||
&a->addr, a->addrlen);
|
||||
} else {
|
||||
log_addr(VERB_ALGO, "skip addr on the donotquery list",
|
||||
&a->addr, a->addrlen);
|
||||
return -1; /* server is on the donotquery list */
|
||||
}
|
||||
}
|
||||
if(!iter_env->supports_ipv6 && addr_is_ip6(&a->addr, a->addrlen)) {
|
||||
return -1; /* there is no ip6 available */
|
||||
@@ -1292,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;
|
||||
}
|
||||
@@ -1527,6 +1549,11 @@ iter_stub_fwd_no_cache(struct module_qstate *qstate, struct query_info *qinf,
|
||||
struct delegpt *dp;
|
||||
int nolock = 1;
|
||||
|
||||
log_assert((retdpname && retdpnamelen
|
||||
&& dpname_storage && dpname_storage_len > 0) ||
|
||||
(retdpname == NULL && retdpnamelen == NULL
|
||||
&& dpname_storage == NULL && dpname_storage_len == 0));
|
||||
|
||||
/* Check for stub. */
|
||||
/* Lock both forwards and hints for atomic read. */
|
||||
lock_rw_rdlock(&qstate->env->fwds->lock);
|
||||
@@ -1677,3 +1704,11 @@ 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;
|
||||
}
|
||||
|
||||
@@ -483,4 +483,7 @@ 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);
|
||||
|
||||
#endif /* ITERATOR_ITER_UTILS_H */
|
||||
|
||||
+127
-40
@@ -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) {
|
||||
@@ -297,6 +298,7 @@ error_response_cache(struct module_qstate* qstate, int id, int rcode)
|
||||
struct reply_info err;
|
||||
struct msgreply_entry* msg;
|
||||
if(qstate->no_cache_store) {
|
||||
qstate->error_response_cache = 1;
|
||||
return error_response(qstate, id, rcode);
|
||||
}
|
||||
if(qstate->prefetch_leeway > NORR_TTL) {
|
||||
@@ -733,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));
|
||||
@@ -741,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);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -860,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 */
|
||||
@@ -1485,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
|
||||
@@ -1504,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
|
||||
@@ -2233,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 */
|
||||
@@ -2289,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;
|
||||
}
|
||||
@@ -2309,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;
|
||||
}
|
||||
@@ -2365,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
|
||||
@@ -2787,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");
|
||||
@@ -2838,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. */
|
||||
@@ -2961,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. */
|
||||
@@ -3021,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 */
|
||||
@@ -3034,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];
|
||||
@@ -3047,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);
|
||||
@@ -3073,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);
|
||||
@@ -3111,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
|
||||
@@ -3153,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);
|
||||
iq->chase_to_rd = 0;
|
||||
/* remove TC flag, if this is erroneously set by TCP upstream */
|
||||
iq->response->rep->flags &= ~BIT_TC;
|
||||
@@ -3223,8 +3259,19 @@ processQueryResponse(struct module_qstate* qstate, struct iter_qstate* iq,
|
||||
} else iter_scrub_ds(iq->response, NULL, NULL);
|
||||
if(type == RESPONSE_TYPE_THROWAWAY &&
|
||||
FLAGS_GET_RCODE(iq->response->rep->flags) == LDNS_RCODE_YXDOMAIN) {
|
||||
/* YXDOMAIN is a permanent error, no need to retry */
|
||||
type = RESPONSE_TYPE_ANSWER;
|
||||
/* YXDOMAIN is a permanent error for DNAME expansion overflow
|
||||
* (RFC 6672 Section 2.2). Only accept if the response
|
||||
* contains a DNAME record in the answer section; otherwise
|
||||
* treat as invalid, to make sure the authoritative answer
|
||||
* make sense. */
|
||||
size_t i;
|
||||
for(i=0; i<iq->response->rep->an_numrrsets; i++) {
|
||||
if(ntohs(iq->response->rep->rrsets[i]->rk.type)
|
||||
== LDNS_RR_TYPE_DNAME) {
|
||||
type = RESPONSE_TYPE_ANSWER;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
if(type == RESPONSE_TYPE_CNAME)
|
||||
origtypecname = 1;
|
||||
@@ -3420,7 +3467,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) {
|
||||
@@ -3697,7 +3751,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. */
|
||||
@@ -3748,7 +3803,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);
|
||||
if(type == RESPONSE_TYPE_ANSWER) {
|
||||
qstate->return_rcode = LDNS_RCODE_NOERROR;
|
||||
qstate->return_msg = iq->response;
|
||||
@@ -3867,7 +3923,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);
|
||||
@@ -3879,7 +3935,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);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -3912,7 +3968,8 @@ processDSNSResponse(struct module_qstate* qstate, int id,
|
||||
|
||||
/* 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");
|
||||
@@ -3961,7 +4018,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;
|
||||
@@ -3983,24 +4040,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;
|
||||
@@ -4104,6 +4186,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)");
|
||||
@@ -4357,7 +4440,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;
|
||||
@@ -4519,6 +4605,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 */
|
||||
|
||||
+16
-32
@@ -142,7 +142,7 @@ check_git_repo () {
|
||||
create_temp_dir () {
|
||||
# Creating temp directory
|
||||
info "Creating temporary working directory"
|
||||
temp_dir=`mktemp -t -d unbound-dist-XXXXXX`
|
||||
temp_dir=`mktemp -d unbound-dist-XXXXXX`
|
||||
info "Directory '$temp_dir' created."
|
||||
cd $temp_dir
|
||||
}
|
||||
@@ -409,14 +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"
|
||||
git submodule update --init || error_cleanup "Could not fetch submodule"
|
||||
rm -rf .git .travis.yml .gitattributes .gitmodules .github .gitignore || error_cleanup "Failed to remove .git tracking and ci information"
|
||||
rm -rf simdzone/.git simdzone/.github simdzone/.gitignore \
|
||||
simdzone/configure~ simdzone/config.h.in~ simdzone/autom4te.cache \
|
||||
simdzone/cmake simdzone/CMakeLists.txt simdzone/simdzoneConfig.cmake.in \
|
||||
simdzone/conanfile.txt simdzone/tests simdzone/.readthedocs.yaml \
|
||||
simdzone/doc simdzone/scripts || \
|
||||
error_cleanup "Failed to remove simdzone .git tracking and ci information"
|
||||
rm -rf .git .travis.yml .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
|
||||
@@ -443,14 +436,11 @@ if [ "$DOWIN" = "yes" ]; then
|
||||
replace_version "configure.ac" "$version" "$version2"
|
||||
version="$version2"
|
||||
info "Rebuilding configure script (autoconf) snapshot."
|
||||
autoreconf -fi || error_cleanup "Autoconf failed."
|
||||
autoconf -f || error_cleanup "Autoconf failed."
|
||||
autoheader -f || error_cleanup "Autoheader failed."
|
||||
rm -r autom4te* || echo "ignored"
|
||||
rm -f config.h.in~ || echo "ignore absence of config.h.in~ file."
|
||||
rm -f configure~ || echo "ignore absence of configure~ file."
|
||||
rm -r simdzone/autom4te* || echo "ignored"
|
||||
rm -f simdzone/config.h.in~ || echo "ignore absence of simdzone/config.h.in~ file."
|
||||
rm -f simdzone/configure~ || echo "ignore absence of simdzone/configure~ file."
|
||||
fi
|
||||
|
||||
if test "`uname`" = "Linux"; then
|
||||
@@ -476,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"
|
||||
@@ -495,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"
|
||||
@@ -608,19 +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"
|
||||
git submodule update --init || error_cleanup "Could not fetch submodule"
|
||||
rm -rf .git .travis.yml .gitattributes .gitmodules .github .gitignore || error_cleanup "Failed to remove .git tracking and ci information"
|
||||
rm -rf simdzone/.git simdzone/.github simdzone/.gitignore \
|
||||
simdzone/configure~ simdzone/config.h.in~ simdzone/autom4te.cache \
|
||||
simdzone/cmake simdzone/CMakeLists.txt simdzone/simdzoneConfig.cmake.in \
|
||||
simdzone/conanfile.txt simdzone/tests simdzone/.readthedocs.yaml \
|
||||
simdzone/doc simdzone/scripts || \
|
||||
error_cleanup "Failed to remove simdzone .git tracking and ci information"
|
||||
|
||||
rm -rf .git .travis.yml .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'
|
||||
@@ -634,16 +623,14 @@ 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 -fi || error_cleanup "Autoconf failed."
|
||||
autoreconf -f || error_cleanup "Autoconf failed."
|
||||
|
||||
rm -r autom4te* || error_cleanup "Failed to remove autoconf cache directory."
|
||||
rm -f config.h.in~ || echo "ignore absence of config.h.in~ file."
|
||||
rm -f configure~ || echo "ignore absence of configure~ file."
|
||||
rm -r simdzone/autom4te* || echo "ignored"
|
||||
rm -f simdzone/config.h.in~ || echo "ignore absence of simdzone/config.h.in~ file."
|
||||
rm -f simdzone/configure~ || echo "ignore absence of simdzone/configure~ file."
|
||||
|
||||
info "Building lexer and parser."
|
||||
echo "#include \"config.h\"" > util/configlexer.c || error_cleanup "Failed to create configlexer"
|
||||
@@ -686,13 +673,10 @@ fi
|
||||
|
||||
if [ "$RECONFIGURE" = "yes" ]; then
|
||||
info "Rebuilding configure script (autoconf) snapshot."
|
||||
autoreconf -fi || error_cleanup "Autoconf failed."
|
||||
autoreconf -f || error_cleanup "Autoconf failed."
|
||||
rm -r autom4te* || error_cleanup "Failed to remove autoconf cache directory."
|
||||
rm -f config.h.in~ || echo "ignore absence of config.h.in~ file."
|
||||
rm -f configure~ || echo "ignore absence of configure~ file."
|
||||
rm -r simdzone/autom4te* || echo "ignored"
|
||||
rm -f simdzone/config.h.in~ || echo "ignore absence of simdzone/config.h.in~ file."
|
||||
rm -f simdzone/configure~ || echo "ignore absence of simdzone/configure~ file."
|
||||
fi
|
||||
|
||||
replace_all doc/README
|
||||
@@ -709,7 +693,7 @@ info "Renaming Unbound directory to unbound-$version."
|
||||
cd ..
|
||||
mv unbound unbound-$version || error_cleanup "Failed to rename unbound directory."
|
||||
|
||||
tarfile="$cwd/unbound-$version.tar.gz"
|
||||
tarfile="../unbound-$version.tar.gz"
|
||||
|
||||
if [ -f $tarfile ]; then
|
||||
(question "The file $tarfile already exists. Overwrite?" \
|
||||
@@ -717,7 +701,7 @@ if [ -f $tarfile ]; then
|
||||
fi
|
||||
|
||||
info "Creating tar unbound-$version.tar.gz"
|
||||
tar czf $tarfile unbound-$version || error_cleanup "Failed to create tar file."
|
||||
tar czf ../unbound-$version.tar.gz unbound-$version || error_cleanup "Failed to create tar file."
|
||||
|
||||
cleanup
|
||||
|
||||
|
||||
+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");
|
||||
|
||||
+42
-22
@@ -899,27 +899,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);
|
||||
@@ -973,6 +980,9 @@ respip_rewrite_reply(const struct query_info* qinfo,
|
||||
lock_rw_unlock(&raddr->lock);
|
||||
lock_rw_unlock(&a->lock);
|
||||
lock_rw_unlock(&az->rpz_lock);
|
||||
if(view) {
|
||||
lock_rw_unlock(&view->lock);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
if(rpz_used) {
|
||||
@@ -1111,7 +1121,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};
|
||||
@@ -1148,8 +1164,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;
|
||||
@@ -1163,6 +1181,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
|
||||
@@ -1259,6 +1278,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;
|
||||
|
||||
@@ -0,0 +1,921 @@
|
||||
/*
|
||||
* services/authload.c - 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.
|
||||
*/
|
||||
|
||||
#include "config.h"
|
||||
#include "services/authload.h"
|
||||
#include "daemon/worker.h"
|
||||
#include "daemon/daemon.h"
|
||||
#include "services/authzone.h"
|
||||
#include "libunbound/authload.h"
|
||||
#include "util/net_help.h"
|
||||
#include "util/log.h"
|
||||
#include "util/ub_event.h"
|
||||
#include "util/timeval_func.h"
|
||||
#include "util/data/dname.h"
|
||||
|
||||
/** Get memory use of buffer. */
|
||||
static size_t
|
||||
buffer_get_mem(struct sldns_buffer* buf)
|
||||
{
|
||||
if(!buf) return 0;
|
||||
return sizeof(*buf) + (buf->_data?buf->_capacity:0);
|
||||
}
|
||||
|
||||
/** Auth load notification to string, for descriptive purposes. */
|
||||
static const char*
|
||||
auth_load_notification_to_string(enum auth_load_notification_type status)
|
||||
{
|
||||
switch(status) {
|
||||
case auth_load_notification_exit:
|
||||
return "auth_load_notification_exit";
|
||||
default:
|
||||
break;
|
||||
}
|
||||
return "unknown_auth_load_notification_value";
|
||||
}
|
||||
|
||||
/** delete chunks */
|
||||
static void
|
||||
auth_chunk_list_delete(struct auth_chunk* first)
|
||||
{
|
||||
struct auth_chunk* c = first, *cn;
|
||||
while(c) {
|
||||
cn = c->next;
|
||||
free(c->data);
|
||||
free(c);
|
||||
c = cn;
|
||||
}
|
||||
}
|
||||
|
||||
/** Delete auth load task item */
|
||||
static void
|
||||
auth_load_task_delete(struct auth_load_task* task)
|
||||
{
|
||||
if(!task)
|
||||
return;
|
||||
free(task->name);
|
||||
free(task->host);
|
||||
free(task->file);
|
||||
auth_chunk_list_delete(task->chunks_first);
|
||||
free(task);
|
||||
}
|
||||
|
||||
/** Create new auth load task item */
|
||||
static struct auth_load_task*
|
||||
auth_load_task_create(void)
|
||||
{
|
||||
struct auth_load_task* task = (struct auth_load_task*)calloc(1,
|
||||
sizeof(*task));
|
||||
return task;
|
||||
}
|
||||
|
||||
/** Pick up the work content of task transfer of auth xfr */
|
||||
static int
|
||||
auth_load_task_pickup_xfr(struct auth_load_task* task, struct auth_xfer* xfr)
|
||||
{
|
||||
task->name = memdup(xfr->name, xfr->namelen);
|
||||
if(!task->name)
|
||||
return 0;
|
||||
task->namelen = xfr->namelen;
|
||||
task->dclass = xfr->dclass;
|
||||
if(xfr->task_transfer->master && xfr->task_transfer->master->host) {
|
||||
task->host = strdup(xfr->task_transfer->master->host);
|
||||
if(!task->host)
|
||||
return 0;
|
||||
}
|
||||
if(xfr->task_transfer->master && xfr->task_transfer->master->file) {
|
||||
task->file = strdup(xfr->task_transfer->master->file);
|
||||
if(!task->file)
|
||||
return 0;
|
||||
}
|
||||
if(xfr->task_transfer->master)
|
||||
task->on_http = xfr->task_transfer->master->http;
|
||||
task->on_ixfr = xfr->task_transfer->on_ixfr;
|
||||
task->on_ixfr_is_axfr = xfr->task_transfer->on_ixfr_is_axfr;
|
||||
task->serial = xfr->serial;
|
||||
if(xfr->task_transfer->chunks_first) {
|
||||
task->chunks_first = xfr->task_transfer->chunks_first;
|
||||
task->chunks_last = xfr->task_transfer->chunks_last;
|
||||
task->chunks_total = xfr->task_transfer->chunks_total;
|
||||
/* The task now has the chunks. Remove them from the
|
||||
* xfr structure. */
|
||||
xfr->task_transfer->chunks_first = 0;
|
||||
xfr->task_transfer->chunks_last = 0;
|
||||
xfr->task_transfer->chunks_total = 0;
|
||||
}
|
||||
|
||||
if(task->on_http)
|
||||
task->task_type = AUTH_LOAD_TASK_HTTPCHUNKS;
|
||||
else task->task_type = AUTH_LOAD_TASK_TRANSFER;
|
||||
return 1;
|
||||
}
|
||||
|
||||
/** Create xfr task */
|
||||
static struct auth_load_task*
|
||||
auth_load_task_create_xfr(struct auth_xfer* xfr, struct worker* worker)
|
||||
{
|
||||
struct auth_load_task* task = auth_load_task_create();
|
||||
if(!task) {
|
||||
log_err("out of memory");
|
||||
return 0;
|
||||
}
|
||||
task->worker = worker;
|
||||
if(!auth_load_task_pickup_xfr(task, xfr)) {
|
||||
log_err("out of memory");
|
||||
auth_load_task_delete(task);
|
||||
return 0;
|
||||
}
|
||||
return task;
|
||||
}
|
||||
|
||||
int
|
||||
auth_load_thread_poll_for_quit(struct auth_load_thread* thr)
|
||||
{
|
||||
int inevent, loopexit = 0;
|
||||
uint8_t cmd;
|
||||
ssize_t ret;
|
||||
|
||||
if(!thr)
|
||||
return 0;
|
||||
if(thr->need_to_quit)
|
||||
return 1;
|
||||
/* Is there data? */
|
||||
if(!sock_poll_timeout(thr->commpair[1], 0, 1, 0, &inevent)) {
|
||||
log_err("auth_load_thread_poll_for_quit: poll failed");
|
||||
return 0;
|
||||
}
|
||||
if(!inevent)
|
||||
return 0;
|
||||
|
||||
/* Read the data */
|
||||
while(1) {
|
||||
if(++loopexit > 200) {
|
||||
log_err("auth_load_thread_poll_for_quit: recv loops %s",
|
||||
sock_strerror(errno));
|
||||
return 0;
|
||||
}
|
||||
ret = recv(thr->commpair[1], ((char*)&cmd), sizeof(cmd), 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("auth_load_thread_poll_for_quit: recv: %s",
|
||||
sock_strerror(errno));
|
||||
return 0;
|
||||
} else if(ret == 0) {
|
||||
log_err("auth_load_thread_poll_for_quit: recv: EOF");
|
||||
return 0;
|
||||
}
|
||||
break;
|
||||
}
|
||||
if(cmd == auth_load_notification_exit) {
|
||||
thr->need_to_quit = 1;
|
||||
verbose(VERB_ALGO, "auth load: exit notification received");
|
||||
return 1;
|
||||
}
|
||||
log_err("auth_load_thread_poll_for_quit: unknown notification status "
|
||||
"received: %d %s", cmd, auth_load_notification_to_string(cmd));
|
||||
return 0;
|
||||
}
|
||||
|
||||
/** Signal the worker connected to an auth load thread the status */
|
||||
static void
|
||||
auth_load_thread_signal_worker(struct auth_load_thread* thr, int status)
|
||||
{
|
||||
int outevent, loopexit = 0;
|
||||
ssize_t ret;
|
||||
uint8_t to_send;
|
||||
verbose(VERB_ALGO, "auth load thread: send status %d", status);
|
||||
/* Make a blocking attempt to send. But meanwhile stay responsive,
|
||||
* once in a while for quit commands. In case the server has to quit. */
|
||||
/* see if there is incoming quit signals */
|
||||
if(auth_load_thread_poll_for_quit(thr))
|
||||
return;
|
||||
to_send = (uint8_t)status;
|
||||
while(1) {
|
||||
if(++loopexit > 200) {
|
||||
log_err("auth load thread: could not send status");
|
||||
return;
|
||||
}
|
||||
/* wait for socket to become writable */
|
||||
if(!sock_poll_timeout(thr->commpair[1],
|
||||
200, /* msec wait before check for quit, and loop to
|
||||
wait again. */
|
||||
0, 1, &outevent)) {
|
||||
log_err("auth load thread: poll failed");
|
||||
return;
|
||||
}
|
||||
if(auth_load_thread_poll_for_quit(thr))
|
||||
return;
|
||||
if(!outevent)
|
||||
continue;
|
||||
ret = send(thr->commpair[1], &to_send, 1, 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("auth load thread signal worker: send: %s",
|
||||
sock_strerror(errno));
|
||||
return;
|
||||
} else if(ret < 1) {
|
||||
continue;
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/** Create proxy auth zone structure, that is used to hold the data
|
||||
* that is processed. */
|
||||
static struct auth_zone*
|
||||
auth_zone_create_proxy(uint8_t* nm, size_t nmlen, uint16_t dclass)
|
||||
{
|
||||
struct auth_zone* z = (struct auth_zone*)calloc(1, sizeof(*z));
|
||||
if(!z) {
|
||||
return NULL;
|
||||
}
|
||||
z->node.key = z;
|
||||
z->dclass = dclass;
|
||||
z->namelen = nmlen;
|
||||
z->namelabs = dname_count_labels(nm);
|
||||
z->name = memdup(nm, nmlen);
|
||||
if(!z->name) {
|
||||
free(z);
|
||||
return NULL;
|
||||
}
|
||||
rbtree_init(&z->data, &auth_data_cmp);
|
||||
return z;
|
||||
}
|
||||
|
||||
/** Delete proxy auth zone structure */
|
||||
static void
|
||||
auth_zone_delete_proxy(struct auth_zone* z)
|
||||
{
|
||||
if(!z)
|
||||
return;
|
||||
traverse_postorder(&z->data, auth_data_del, NULL);
|
||||
if(z->rpz)
|
||||
rpz_delete(z->rpz);
|
||||
free(z->name);
|
||||
free(z);
|
||||
}
|
||||
|
||||
/** Calculate memory use of the authload thread for this task.
|
||||
* The size of the task struct, with the data chunks, and the proxy auth zone
|
||||
* structure that is created while the other auth zone is used for queries,
|
||||
* and other added memory.
|
||||
*/
|
||||
static void
|
||||
auth_load_calc_mem(struct auth_load_task* task, struct auth_zone* z,
|
||||
size_t other)
|
||||
{
|
||||
size_t m = 0;
|
||||
if(verbosity < 8) {
|
||||
task->mem_used = 0;
|
||||
return;
|
||||
}
|
||||
m += other;
|
||||
m += sizeof(*task);
|
||||
m += task->namelen;
|
||||
m += getmem_str(task->host);
|
||||
m += getmem_str(task->file);
|
||||
m += task->chunks_total;
|
||||
m += auth_zone_get_mem(z);
|
||||
task->mem_used = m;
|
||||
}
|
||||
|
||||
/** Swap the final zone contents with the live zone */
|
||||
static void
|
||||
auth_load_swap_zone(struct auth_load_thread* thr, struct auth_zone* proxyz)
|
||||
{
|
||||
rbtree_type data;
|
||||
struct rpz* rpz;
|
||||
struct auth_zone* z;
|
||||
lock_rw_rdlock(&thr->task->worker->env.auth_zones->lock);
|
||||
z = auth_zone_find(thr->task->worker->env.auth_zones,
|
||||
thr->task->name, thr->task->namelen, thr->task->dclass);
|
||||
if(!z) {
|
||||
lock_rw_unlock(&thr->task->worker->env.auth_zones->lock);
|
||||
verbose(VERB_ALGO, "auth zone missing after auth load.");
|
||||
return;
|
||||
}
|
||||
lock_rw_wrlock(&z->lock);
|
||||
lock_rw_unlock(&thr->task->worker->env.auth_zones->lock);
|
||||
|
||||
data = proxyz->data;
|
||||
proxyz->data = z->data;
|
||||
z->data = data;
|
||||
|
||||
rpz = proxyz->rpz;
|
||||
proxyz->rpz = z->rpz;
|
||||
z->rpz = rpz;
|
||||
|
||||
lock_rw_unlock(&z->lock);
|
||||
}
|
||||
|
||||
/** Process http transfer */
|
||||
static int
|
||||
auth_load_process_http(struct auth_load_thread* thr)
|
||||
{
|
||||
struct auth_load_task* task = thr->task;
|
||||
struct sldns_buffer* scratch_buffer;
|
||||
struct auth_zone* z;
|
||||
size_t scratch_mem;
|
||||
|
||||
scratch_buffer = sldns_buffer_new(sldns_buffer_capacity(
|
||||
thr->task->worker->env.scratch_buffer));
|
||||
if(!scratch_buffer) {
|
||||
log_err("out of memory");
|
||||
return 0;
|
||||
}
|
||||
scratch_mem = buffer_get_mem(scratch_buffer);
|
||||
z = auth_zone_create_proxy(task->name, task->namelen, task->dclass);
|
||||
if(!z) {
|
||||
log_err("out of memory");
|
||||
sldns_buffer_free(scratch_buffer);
|
||||
return 0;
|
||||
}
|
||||
if(auth_load_thread_poll_for_quit(thr)) {
|
||||
sldns_buffer_free(scratch_buffer);
|
||||
auth_zone_delete_proxy(z);
|
||||
return 0;
|
||||
}
|
||||
|
||||
xfr_http_preview(task->file, task->chunks_first);
|
||||
if(!xfr_http_syntax_check(task->name, task->namelen, task->dclass,
|
||||
task->host, task->file, task->chunks_first, scratch_buffer)) {
|
||||
sldns_buffer_free(scratch_buffer);
|
||||
auth_zone_delete_proxy(z);
|
||||
return 0;
|
||||
}
|
||||
if(auth_load_thread_poll_for_quit(thr)) {
|
||||
sldns_buffer_free(scratch_buffer);
|
||||
auth_zone_delete_proxy(z);
|
||||
return 0;
|
||||
}
|
||||
if(!xfr_apply_http(task->name, task->namelen, task->host, task->file,
|
||||
task->chunks_first, z, scratch_buffer, thr)) {
|
||||
sldns_buffer_free(scratch_buffer);
|
||||
auth_zone_delete_proxy(z);
|
||||
return 0;
|
||||
}
|
||||
sldns_buffer_free(scratch_buffer);
|
||||
if(z->rpz)
|
||||
rpz_finish_config(z->rpz);
|
||||
if(auth_load_thread_poll_for_quit(thr)) {
|
||||
auth_zone_delete_proxy(z);
|
||||
return 0;
|
||||
}
|
||||
|
||||
auth_load_calc_mem(task, z, scratch_mem);
|
||||
auth_load_swap_zone(thr, z);
|
||||
auth_zone_delete_proxy(z);
|
||||
return 1;
|
||||
}
|
||||
|
||||
/** Copy RRset and append it to the domain, update last pointer. */
|
||||
static int
|
||||
rrset_append_copy(struct auth_data* domain, struct auth_rrset* rrset,
|
||||
struct auth_rrset** last)
|
||||
{
|
||||
struct auth_rrset* s = calloc(1, sizeof(*s));
|
||||
if(!s)
|
||||
return 0;
|
||||
s->type = rrset->type;
|
||||
s->data = (struct packed_rrset_data*)memdup(rrset->data,
|
||||
packed_rrset_sizeof(rrset->data));
|
||||
if(!s->data) {
|
||||
free(s);
|
||||
return 0;
|
||||
}
|
||||
packed_rrset_ptr_fixup(s->data);
|
||||
if(!*last)
|
||||
domain->rrsets = s;
|
||||
else (*last)->next = s;
|
||||
*last = s;
|
||||
return 1;
|
||||
}
|
||||
|
||||
/** Copy the existing zone for modification */
|
||||
static int
|
||||
auth_load_copy_into_zone(struct auth_load_thread* thr, struct auth_zone* proxyz)
|
||||
{
|
||||
int count = 0;
|
||||
struct auth_zone* z;
|
||||
struct auth_data* d;
|
||||
lock_rw_rdlock(&thr->task->worker->env.auth_zones->lock);
|
||||
z = auth_zone_find(thr->task->worker->env.auth_zones,
|
||||
thr->task->name, thr->task->namelen, thr->task->dclass);
|
||||
if(!z) {
|
||||
lock_rw_unlock(&thr->task->worker->env.auth_zones->lock);
|
||||
verbose(VERB_ALGO, "auth zone missing for copy for IXFR.");
|
||||
return 0;
|
||||
}
|
||||
lock_rw_rdlock(&z->lock);
|
||||
lock_rw_unlock(&thr->task->worker->env.auth_zones->lock);
|
||||
|
||||
/* Copy from z into proxyz. */
|
||||
RBTREE_FOR(d, struct auth_data*, &z->data) {
|
||||
struct auth_rrset* rrset, *last = NULL;
|
||||
struct auth_data* proxy_d = az_domain_create(proxyz,
|
||||
d->name, d->namelen);
|
||||
if(!proxy_d) {
|
||||
log_err("out of memory");
|
||||
lock_rw_unlock(&z->lock);
|
||||
return 0;
|
||||
}
|
||||
for(rrset = d->rrsets; rrset; rrset=rrset->next) {
|
||||
if(!rrset_append_copy(proxy_d, rrset, &last)) {
|
||||
log_err("out of memory");
|
||||
lock_rw_unlock(&z->lock);
|
||||
return 0;
|
||||
}
|
||||
if((count++)%10000 == 0) {
|
||||
if(auth_load_thread_poll_for_quit(thr)) {
|
||||
lock_rw_unlock(&z->lock);
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
if((count++)%10000 == 0) {
|
||||
if(auth_load_thread_poll_for_quit(thr)) {
|
||||
lock_rw_unlock(&z->lock);
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
lock_rw_unlock(&z->lock);
|
||||
return 1;
|
||||
}
|
||||
|
||||
/** Process ixfr transfer */
|
||||
static int
|
||||
auth_load_process_ixfr(struct auth_load_thread* thr)
|
||||
{
|
||||
struct auth_load_task* task = thr->task;
|
||||
struct sldns_buffer* scratch_buffer;
|
||||
struct auth_zone* z;
|
||||
size_t scratch_mem;
|
||||
|
||||
scratch_buffer = sldns_buffer_new(sldns_buffer_capacity(
|
||||
thr->task->worker->env.scratch_buffer));
|
||||
if(!scratch_buffer) {
|
||||
log_err("out of memory");
|
||||
return 0;
|
||||
}
|
||||
scratch_mem = buffer_get_mem(scratch_buffer);
|
||||
z = auth_zone_create_proxy(task->name, task->namelen, task->dclass);
|
||||
if(!z) {
|
||||
log_err("out of memory");
|
||||
sldns_buffer_free(scratch_buffer);
|
||||
return 0;
|
||||
}
|
||||
if(auth_load_thread_poll_for_quit(thr)) {
|
||||
sldns_buffer_free(scratch_buffer);
|
||||
auth_zone_delete_proxy(z);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Copy the existing zone for modification, that uses a read lock.
|
||||
* That then does not interrupt the service of threads. */
|
||||
if(!auth_load_copy_into_zone(thr, z)) {
|
||||
sldns_buffer_free(scratch_buffer);
|
||||
auth_zone_delete_proxy(z);
|
||||
return 0;
|
||||
}
|
||||
if(!xfr_apply_ixfr(task->chunks_first, task->serial, z,
|
||||
scratch_buffer, thr)) {
|
||||
sldns_buffer_free(scratch_buffer);
|
||||
auth_zone_delete_proxy(z);
|
||||
return 0;
|
||||
}
|
||||
sldns_buffer_free(scratch_buffer);
|
||||
if(auth_load_thread_poll_for_quit(thr)) {
|
||||
auth_zone_delete_proxy(z);
|
||||
return 0;
|
||||
}
|
||||
|
||||
auth_load_calc_mem(task, z, scratch_mem);
|
||||
auth_load_swap_zone(thr, z);
|
||||
auth_zone_delete_proxy(z);
|
||||
return 1;
|
||||
}
|
||||
|
||||
/** Process axfr transfer */
|
||||
static int
|
||||
auth_load_process_axfr(struct auth_load_thread* thr)
|
||||
{
|
||||
struct auth_load_task* task = thr->task;
|
||||
struct sldns_buffer* scratch_buffer;
|
||||
struct auth_zone* z;
|
||||
size_t scratch_mem;
|
||||
|
||||
scratch_buffer = sldns_buffer_new(sldns_buffer_capacity(
|
||||
thr->task->worker->env.scratch_buffer));
|
||||
if(!scratch_buffer) {
|
||||
log_err("out of memory");
|
||||
return 0;
|
||||
}
|
||||
scratch_mem = buffer_get_mem(scratch_buffer);
|
||||
z = auth_zone_create_proxy(task->name, task->namelen, task->dclass);
|
||||
if(!z) {
|
||||
log_err("out of memory");
|
||||
sldns_buffer_free(scratch_buffer);
|
||||
return 0;
|
||||
}
|
||||
if(auth_load_thread_poll_for_quit(thr)) {
|
||||
sldns_buffer_free(scratch_buffer);
|
||||
auth_zone_delete_proxy(z);
|
||||
return 0;
|
||||
}
|
||||
|
||||
if(!xfr_apply_axfr(task->chunks_first, z, scratch_buffer, thr)) {
|
||||
sldns_buffer_free(scratch_buffer);
|
||||
auth_zone_delete_proxy(z);
|
||||
return 0;
|
||||
}
|
||||
sldns_buffer_free(scratch_buffer);
|
||||
if(auth_load_thread_poll_for_quit(thr)) {
|
||||
auth_zone_delete_proxy(z);
|
||||
return 0;
|
||||
}
|
||||
|
||||
auth_load_calc_mem(task, z, scratch_mem);
|
||||
auth_load_swap_zone(thr, z);
|
||||
auth_zone_delete_proxy(z);
|
||||
return 1;
|
||||
}
|
||||
|
||||
|
||||
/** In the auth load thread, process the task */
|
||||
static int
|
||||
auth_load_thread_process(struct auth_load_thread* thr)
|
||||
{
|
||||
struct auth_load_task* task = thr->task;
|
||||
struct timeval start, end;
|
||||
if(gettimeofday(&start, NULL) < 0)
|
||||
log_err("gettimeofday: %s", strerror(errno));
|
||||
|
||||
/* apply data */
|
||||
if(task->on_http) {
|
||||
if(!auth_load_process_http(thr))
|
||||
return 0;
|
||||
} else if(task->on_ixfr && !task->on_ixfr_is_axfr) {
|
||||
if(!auth_load_process_ixfr(thr))
|
||||
return 0;
|
||||
} else {
|
||||
if(!auth_load_process_axfr(thr))
|
||||
return 0;
|
||||
}
|
||||
|
||||
if(gettimeofday(&end, NULL) < 0)
|
||||
log_err("gettimeofday: %s", strerror(errno));
|
||||
timeval_subtract(&thr->task->time_taken, &end, &start);
|
||||
return 1;
|
||||
}
|
||||
|
||||
/** The auth load thread. The thread main function. */
|
||||
static void*
|
||||
auth_load_thread_main(void* arg)
|
||||
{
|
||||
struct auth_load_thread* thr = (struct auth_load_thread*)arg;
|
||||
int s;
|
||||
const char name[16] = "unbound/authld"; /* seems to be the safest size
|
||||
between different OSes */
|
||||
|
||||
#if defined(HAVE_GETTID) && !defined(THREADS_DISABLED)
|
||||
thr->thread_tid = gettid();
|
||||
if(thr->thread_tid_log)
|
||||
log_thread_set(&thr->thread_tid);
|
||||
else
|
||||
#endif
|
||||
log_thread_set(&thr->threadnum);
|
||||
|
||||
ub_thread_setname(ub_thread_self(), name);
|
||||
(void)name; /* When setname is not defined, ignore the name variable. */
|
||||
|
||||
verbose(VERB_ALGO, "start auth load thread");
|
||||
s = auth_load_thread_process(thr);
|
||||
/* The result is sent to the worker, that reaps the thread. */
|
||||
auth_load_thread_signal_worker(thr, s);
|
||||
verbose(VERB_ALGO, "stop auth load thread");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/** Delete auth load thread structure */
|
||||
static void
|
||||
auth_load_thread_delete(struct auth_load_thread* thr)
|
||||
{
|
||||
if(!thr)
|
||||
return;
|
||||
if(thr->service_event && thr->service_event_is_added) {
|
||||
ub_event_del(thr->service_event);
|
||||
thr->service_event_is_added = 0;
|
||||
}
|
||||
if(thr->service_event)
|
||||
ub_event_free(thr->service_event);
|
||||
if(thr->commpair[0] != -1)
|
||||
sock_close(thr->commpair[0]);
|
||||
if(thr->commpair[1] != -1)
|
||||
sock_close(thr->commpair[1]);
|
||||
auth_load_task_delete(thr->task);
|
||||
free(thr);
|
||||
}
|
||||
|
||||
/** Create auth load thread structure */
|
||||
static struct auth_load_thread*
|
||||
auth_load_thread_create(struct auth_load_task* task)
|
||||
{
|
||||
int numworkers;
|
||||
struct auth_load_thread* thr = (struct auth_load_thread*)calloc(1,
|
||||
sizeof(*thr));
|
||||
if(!thr)
|
||||
return NULL;
|
||||
numworkers = task->worker->daemon->num;
|
||||
/* This number is printed into the logs */
|
||||
thr->threadnum = numworkers+3;
|
||||
thr->task = task;
|
||||
thr->commpair[0] = -1;
|
||||
thr->commpair[1] = -1;
|
||||
if(!create_socketpair(thr->commpair, task->worker->daemon->rand)) {
|
||||
auth_load_thread_delete(thr);
|
||||
return NULL;
|
||||
}
|
||||
#ifdef HAVE_GETTID
|
||||
thr->thread_tid_log = task->worker->env.cfg->log_thread_id;
|
||||
#endif
|
||||
return thr;
|
||||
}
|
||||
|
||||
/** The worker routine that services the auth load connection. */
|
||||
void
|
||||
worker_auth_load_service_cb(int ATTR_UNUSED(fd), short ATTR_UNUSED(bits),
|
||||
void* arg)
|
||||
{
|
||||
struct auth_load_thread* thr = (struct auth_load_thread*)arg;
|
||||
uint8_t recv_item;
|
||||
ssize_t ret;
|
||||
struct auth_xfer* xfr;
|
||||
struct auth_chunk* chunk_list;
|
||||
struct module_env* env = &thr->task->worker->env;
|
||||
int ixfr_fail;
|
||||
struct timeval time_taken;
|
||||
size_t mem_used, chunks_total;
|
||||
|
||||
log_assert(thr->commpair[0] >= 0);
|
||||
ret = recv(thr->commpair[0], &recv_item, 1, 0);
|
||||
if(ret == -1) {
|
||||
if(
|
||||
#ifndef USE_WINSOCK
|
||||
errno == EINTR || errno == EAGAIN
|
||||
# ifdef EWOULDBLOCK
|
||||
|| errno == EWOULDBLOCK
|
||||
# endif
|
||||
#else
|
||||
WSAGetLastError() == WSAEINTR ||
|
||||
WSAGetLastError() == WSAEINPROGRESS
|
||||
#endif
|
||||
)
|
||||
return; /* Continue later. */
|
||||
#ifdef USE_WINSOCK
|
||||
if(WSAGetLastError() == WSAEWOULDBLOCK) {
|
||||
ub_winsock_tcp_wouldblock(thr->service_event,
|
||||
UB_EV_READ);
|
||||
return; /* Continue later. */
|
||||
}
|
||||
#endif
|
||||
log_err("read status from auth load thread, recv: %s",
|
||||
sock_strerror(errno));
|
||||
return;
|
||||
} else if(ret == 0) {
|
||||
verbose(VERB_ALGO, "closed connection from auth load thread");
|
||||
/* handle this like an error */
|
||||
recv_item = 0;
|
||||
/* ret<1: No short read on 1 byte, to continue later on */
|
||||
}
|
||||
|
||||
/* Deal with the result of auth load thread */
|
||||
verbose(VERB_ALGO, "auth load status is %d", (int)recv_item);
|
||||
verbose(VERB_ALGO, "join with auth load thread");
|
||||
ub_thread_join(thr->tid);
|
||||
verbose(VERB_ALGO, "joined with auth load thread");
|
||||
lock_rw_rdlock(&thr->task->worker->env.auth_zones->lock);
|
||||
xfr = auth_xfer_find(thr->task->worker->env.auth_zones,
|
||||
thr->task->name, thr->task->namelen, thr->task->dclass);
|
||||
if(!xfr) {
|
||||
lock_rw_unlock(&thr->task->worker->env.auth_zones->lock);
|
||||
verbose(VERB_ALGO, "auth load: xfr is gone");
|
||||
auth_load_thread_delete(thr);
|
||||
auth_load_info_release_thread(env);
|
||||
return;
|
||||
}
|
||||
lock_basic_lock(&xfr->lock);
|
||||
lock_rw_unlock(&thr->task->worker->env.auth_zones->lock);
|
||||
ixfr_fail = thr->task->ixfr_fail;
|
||||
time_taken = thr->task->time_taken;
|
||||
mem_used = thr->task->mem_used;
|
||||
chunks_total = thr->task->chunks_total;
|
||||
if(thr->task->on_http) {
|
||||
chunk_list = thr->task->chunks_first;
|
||||
thr->task->chunks_first = NULL;
|
||||
thr->task->chunks_last = NULL;
|
||||
thr->task->chunks_total = 0;
|
||||
} else {
|
||||
chunk_list = NULL;
|
||||
}
|
||||
auth_load_thread_delete(thr);
|
||||
auth_load_info_release_thread(env);
|
||||
xfr_process_load_end_transfer(xfr, env, recv_item, ixfr_fail,
|
||||
&time_taken, mem_used, chunks_total, chunk_list);
|
||||
}
|
||||
|
||||
/** Attach worker to the auth load thread. */
|
||||
static int
|
||||
auth_load_thread_attach(struct auth_load_thread* thr, struct worker* worker)
|
||||
{
|
||||
/* Setup listener in worker, that connects via a pipe to the
|
||||
* auth load thread.
|
||||
* The listener has to be nonblocking, so the the remote servicing
|
||||
* thread can continue to service DNS queries.
|
||||
* The commpair[1] element can stay blocking, it is used by the
|
||||
* auth load thread. The thread needs to wait at these times, when
|
||||
* it has to check briefly it can use poll. */
|
||||
verbose(VERB_ALGO, "auth_load_thread_attach");
|
||||
fd_set_nonblock(thr->commpair[0]);
|
||||
if(!comm_base_internal(worker->base)) {
|
||||
verbose(VERB_ALGO, "auth load thread: no event base");
|
||||
return 0;
|
||||
}
|
||||
thr->service_event = ub_event_new(comm_base_internal(worker->base),
|
||||
thr->commpair[0], UB_EV_READ | UB_EV_PERSIST,
|
||||
worker_auth_load_service_cb, thr);
|
||||
if(!thr->service_event) {
|
||||
log_err("out of memory");
|
||||
return 0;
|
||||
}
|
||||
if(ub_event_add(thr->service_event, NULL) != 0) {
|
||||
log_err("out of memory");
|
||||
return 0;
|
||||
}
|
||||
thr->service_event_is_added = 1;
|
||||
return 1;
|
||||
}
|
||||
|
||||
/** Create and start the auth load thread, with the task */
|
||||
static int
|
||||
auth_load_start_thread(struct auth_load_task* task)
|
||||
{
|
||||
struct auth_load_thread* thr = auth_load_thread_create(task);
|
||||
if(!thr) {
|
||||
log_err("out of memory");
|
||||
auth_load_task_delete(task);
|
||||
return 0;
|
||||
}
|
||||
if(!auth_load_thread_attach(thr, task->worker)) {
|
||||
log_err("out of memory");
|
||||
auth_load_thread_delete(thr);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Start auth load thread */
|
||||
ub_thread_create(&thr->tid, auth_load_thread_main, thr);
|
||||
return 1;
|
||||
}
|
||||
|
||||
int auth_load_add_task_xfr(struct auth_xfer* xfr, struct worker* worker)
|
||||
{
|
||||
struct auth_load_task* task;
|
||||
int can_run = 0;
|
||||
verbose(VERB_ALGO, "auth load add task");
|
||||
|
||||
/* Check auth load count */
|
||||
can_run = 1;
|
||||
|
||||
/* Create new thread */
|
||||
task = auth_load_task_create_xfr(xfr, worker);
|
||||
if(!task)
|
||||
return 0;
|
||||
if(can_run) {
|
||||
verbose(VERB_ALGO, "auth load start thread");
|
||||
if(!auth_load_start_thread(task))
|
||||
return 0;
|
||||
verbose(VERB_ALGO, "auth load thread started");
|
||||
return 1;
|
||||
}
|
||||
|
||||
/* Make wait item */
|
||||
return 0;
|
||||
}
|
||||
|
||||
struct auth_load_general_info* auth_load_info_create(void)
|
||||
{
|
||||
struct auth_load_general_info* auth_load_info =
|
||||
(struct auth_load_general_info*)calloc(1,
|
||||
sizeof(*auth_load_info));
|
||||
if(!auth_load_info) {
|
||||
log_err("malloc failure");
|
||||
return NULL;
|
||||
}
|
||||
lock_basic_init(&auth_load_info->lock);
|
||||
lock_protect(&auth_load_info->lock,
|
||||
&auth_load_info->num_auth_load_threads,
|
||||
sizeof(auth_load_info->num_auth_load_threads));
|
||||
return auth_load_info;
|
||||
}
|
||||
|
||||
void auth_load_info_delete(struct auth_load_general_info* auth_load_info)
|
||||
{
|
||||
if(!auth_load_info)
|
||||
return;
|
||||
lock_basic_destroy(&auth_load_info->lock);
|
||||
free(auth_load_info);
|
||||
}
|
||||
|
||||
int auth_load_info_grab_thread(struct module_env* env)
|
||||
{
|
||||
struct auth_load_general_info* auth_load_info =
|
||||
env->worker->daemon->auth_load_info;
|
||||
struct config_file* cfg = env->cfg;
|
||||
int ret = 0;
|
||||
lock_basic_lock(&auth_load_info->lock);
|
||||
if(auth_load_info->num_auth_load_threads < cfg->auth_task_threads) {
|
||||
ret = 1;
|
||||
auth_load_info->num_auth_load_threads++;
|
||||
}
|
||||
lock_basic_unlock(&auth_load_info->lock);
|
||||
return ret;
|
||||
}
|
||||
|
||||
void auth_load_info_release_thread(struct module_env* env)
|
||||
{
|
||||
struct auth_load_general_info* auth_load_info =
|
||||
env->worker->daemon->auth_load_info;
|
||||
lock_basic_lock(&auth_load_info->lock);
|
||||
if(auth_load_info->num_auth_load_threads == 0) {
|
||||
verbose(VERB_ALGO, "release of auth load thread, but "
|
||||
"num_auth_load_threads not > 0.");
|
||||
} else {
|
||||
auth_load_info->num_auth_load_threads--;
|
||||
}
|
||||
lock_basic_unlock(&auth_load_info->lock);
|
||||
}
|
||||
@@ -0,0 +1,203 @@
|
||||
/*
|
||||
* 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"
|
||||
struct worker;
|
||||
struct auth_xfer;
|
||||
struct module_env;
|
||||
struct auth_load_task;
|
||||
|
||||
/**
|
||||
* General information for auth load threads. The number of active threads.
|
||||
*/
|
||||
struct auth_load_general_info {
|
||||
/** lock on this structure */
|
||||
lock_basic_type lock;
|
||||
/** The number of active auth load threads. */
|
||||
int num_auth_load_threads;
|
||||
};
|
||||
|
||||
/**
|
||||
* 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;
|
||||
|
||||
/** 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;
|
||||
|
||||
/** 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;
|
||||
/** 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, or makes a wait list item.
|
||||
* @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);
|
||||
|
||||
/** 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);
|
||||
|
||||
#endif /* SERVICES_AUTHLOAD_H */
|
||||
+757
-603
File diff suppressed because it is too large
Load Diff
@@ -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,8 @@ 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;
|
||||
/** zone has been deleted */
|
||||
int zone_deleted;
|
||||
/** deletelist pointer, unused normally except during delete */
|
||||
@@ -153,6 +156,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 +290,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 +347,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 +397,18 @@ 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;
|
||||
|
||||
/** 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;
|
||||
|
||||
@@ -828,4 +852,48 @@ 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);
|
||||
|
||||
/** 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, size_t mem_used, size_t chunks_total,
|
||||
struct auth_chunk* chunk_list);
|
||||
|
||||
/** 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
+43
-9
@@ -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"
|
||||
@@ -232,8 +233,15 @@ find_closest_of_type(struct module_env* env, uint8_t* qname, size_t qnamelen,
|
||||
|
||||
/* snip off front part of qname until the type is found */
|
||||
while(qnamelen > 0) {
|
||||
if((rrset = rrset_cache_lookup(env->rrset_cache, qname,
|
||||
qnamelen, searchtype, qclass, 0, now, 0))) {
|
||||
rrset = rrset_cache_lookup(env->rrset_cache, qname,
|
||||
qnamelen, searchtype, qclass, 0, now, 0);
|
||||
if(!rrset && searchtype == LDNS_RR_TYPE_DNAME)
|
||||
/* If not found, for type DNAME, try 0TTL stored,
|
||||
* for its grace period. */
|
||||
rrset = rrset_cache_lookup(env->rrset_cache, qname,
|
||||
qnamelen, searchtype, qclass,
|
||||
PACKED_RRSET_UPSTREAM_0TTL, now, 0);
|
||||
if(rrset) {
|
||||
uint8_t* origqname = qname;
|
||||
size_t origqnamelen = qnamelen;
|
||||
if(!noexpiredabove)
|
||||
@@ -270,6 +278,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;
|
||||
}
|
||||
@@ -577,8 +587,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)
|
||||
@@ -705,10 +719,16 @@ struct dns_msg*
|
||||
dns_msg_deepcopy_region(struct dns_msg* origin, struct regional* region)
|
||||
{
|
||||
size_t i;
|
||||
struct ub_packed_rrset_key** saved_rrsets;
|
||||
struct dns_msg* res = NULL;
|
||||
size_t rep_alloc_size = sizeof(struct reply_info)
|
||||
- sizeof(struct rrset_ref); /* this is the size of res->rep
|
||||
allocated in gen_dns_msg() */
|
||||
res = gen_dns_msg(region, &origin->qinfo, origin->rep->rrset_count);
|
||||
if(!res) return NULL;
|
||||
*res->rep = *origin->rep;
|
||||
saved_rrsets = res->rep->rrsets; /* save rrsets alloc by gen_dns_msg */
|
||||
memcpy(res->rep, origin->rep, rep_alloc_size);
|
||||
res->rep->rrsets = saved_rrsets;
|
||||
if(origin->rep->reason_bogus_str) {
|
||||
res->rep->reason_bogus_str = regional_strdup(region,
|
||||
origin->rep->reason_bogus_str);
|
||||
@@ -766,8 +786,20 @@ synth_dname_msg(struct ub_packed_rrset_key* rrset, struct regional* region,
|
||||
rrset->entry.data;
|
||||
uint8_t* newname, *dtarg = NULL;
|
||||
size_t newlen, dtarglen;
|
||||
if(TTL_IS_EXPIRED(d->ttl, now))
|
||||
return NULL;
|
||||
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;
|
||||
}
|
||||
/* only allow validated (with DNSSEC) DNAMEs used from cache
|
||||
* for insecure DNAMEs, query again. */
|
||||
*sec_status = d->security;
|
||||
@@ -779,7 +811,7 @@ synth_dname_msg(struct ub_packed_rrset_key* rrset, struct regional* region,
|
||||
msg->rep->flags = BIT_QR; /* reply, no AA, no error */
|
||||
msg->rep->authoritative = 0; /* reply stored in cache can't be authoritative */
|
||||
msg->rep->qdcount = 1;
|
||||
msg->rep->ttl = d->ttl - now;
|
||||
msg->rep->ttl = rr_ttl;
|
||||
msg->rep->prefetch_ttl = PREFETCH_TTL_CALC(msg->rep->ttl);
|
||||
msg->rep->serve_expired_ttl = msg->rep->ttl + SERVE_EXPIRED_TTL;
|
||||
msg->rep->serve_expired_norec_ttl = 0;
|
||||
@@ -792,6 +824,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)
|
||||
@@ -831,7 +865,7 @@ synth_dname_msg(struct ub_packed_rrset_key* rrset, struct regional* region,
|
||||
if(!newd)
|
||||
return NULL;
|
||||
ck->entry.data = newd;
|
||||
newd->ttl = d->ttl - now; /* RFC6672: synth CNAME TTL == DNAME TTL */
|
||||
newd->ttl = rr_ttl; /* RFC6672: synth CNAME TTL == DNAME TTL */
|
||||
newd->count = 1;
|
||||
newd->rrsig_count = 0;
|
||||
newd->trust = rrset_trust_ans_noAA;
|
||||
@@ -1045,7 +1079,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);
|
||||
|
||||
Vendored
+81
-10
@@ -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;
|
||||
@@ -149,6 +151,20 @@ need_to_update_rrset(void* nd, void* cd, time_t timenow, int equal, int ns)
|
||||
if(equal && !TTL_IS_EXPIRED(cached->ttl, timenow) &&
|
||||
cached->security == sec_status_bogus)
|
||||
return 0;
|
||||
/* ghost-domain: never let an NS overwrite extend lifetime
|
||||
* past the entry it replaces, regardless of trust. */
|
||||
/* 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)
|
||||
newd->rr_ttl[i] = newd->ttl;
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
/* o item in cache has expired */
|
||||
@@ -199,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
|
||||
@@ -213,7 +236,8 @@ 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 */
|
||||
lock_rw_unlock(&e->lock);
|
||||
ub_packed_rrset_parsedelete(k, alloc);
|
||||
@@ -245,12 +269,45 @@ rrset_cache_update(struct rrset_cache* r, struct rrset_ref* ref,
|
||||
return 0;
|
||||
}
|
||||
|
||||
/** 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");
|
||||
@@ -262,14 +319,16 @@ 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;
|
||||
@@ -278,6 +337,10 @@ void rrset_cache_update_wildcard(struct rrset_cache* rrset_cache,
|
||||
(void)rrset_cache_update(rrset_cache, &ref, alloc, timenow);
|
||||
}
|
||||
|
||||
/** Grace period in seconds for TTL=0 DNAME rrsets (RFC 2308: do not cache).
|
||||
* Allows synthesis from cache within this window to reduce recursion load. */
|
||||
#define DNAME_TTL0_GRACE_SECONDS 1
|
||||
|
||||
struct ub_packed_rrset_key*
|
||||
rrset_cache_lookup(struct rrset_cache* r, uint8_t* qname, size_t qnamelen,
|
||||
uint16_t qtype, uint16_t qclass, uint32_t flags, time_t timenow,
|
||||
@@ -300,12 +363,20 @@ rrset_cache_lookup(struct rrset_cache* r, uint8_t* qname, size_t qnamelen,
|
||||
/* check TTL */
|
||||
struct packed_rrset_data* data =
|
||||
(struct packed_rrset_data*)e->data;
|
||||
struct ub_packed_rrset_key* k = (struct ub_packed_rrset_key*)e->key;
|
||||
if(TTL_IS_EXPIRED(data->ttl, timenow)) {
|
||||
lock_rw_unlock(&e->lock);
|
||||
return NULL;
|
||||
/* Allow TTL=0 DNAME within grace period for synthesis */
|
||||
if(qtype == LDNS_RR_TYPE_DNAME &&
|
||||
(k->rk.flags & PACKED_RRSET_UPSTREAM_0TTL) &&
|
||||
(timenow - data->ttl_add) <= DNAME_TTL0_GRACE_SECONDS) {
|
||||
/* within grace: allow for synthesis */
|
||||
} else {
|
||||
lock_rw_unlock(&e->lock);
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
/* we're done */
|
||||
return (struct ub_packed_rrset_key*)e->key;
|
||||
return k;
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
+190
-99
@@ -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);
|
||||
@@ -2167,7 +2184,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;
|
||||
}
|
||||
@@ -2300,21 +2318,8 @@ int
|
||||
tcp_req_info_handle_read_close(struct tcp_req_info* req)
|
||||
{
|
||||
verbose(VERB_ALGO, "tcp channel read side closed %d", req->cp->fd);
|
||||
/* reset byte count for (potential) partial read */
|
||||
req->cp->tcp_byte_count = 0;
|
||||
/* if we still have results to write, pick up next and write it */
|
||||
if(req->num_done_req != 0) {
|
||||
tcp_req_pickup_next_result(req);
|
||||
tcp_req_info_setup_listen(req);
|
||||
return 1;
|
||||
}
|
||||
/* if nothing to do, this closes the connection */
|
||||
if(req->num_open_req == 0 && req->num_done_req == 0)
|
||||
return 0;
|
||||
/* otherwise, we must be waiting for dns resolve, wait with timeout */
|
||||
req->read_is_closed = 1;
|
||||
tcp_req_info_setup_listen(req);
|
||||
return 1;
|
||||
/* RFC 7766 6.2.4 says to drop pending replies when client closes. */
|
||||
return 0; /* drop connection */
|
||||
}
|
||||
|
||||
void
|
||||
@@ -3412,14 +3417,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;
|
||||
@@ -3467,7 +3471,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;
|
||||
@@ -3513,7 +3517,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) {
|
||||
@@ -3527,14 +3532,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. */
|
||||
@@ -3610,15 +3615,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)
|
||||
@@ -3638,9 +3657,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);
|
||||
@@ -3713,13 +3737,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;
|
||||
}
|
||||
@@ -3780,7 +3800,7 @@ doq_repinfo_retrieve_localaddr(struct comm_reply* repinfo,
|
||||
memset(sa6, 0, *localaddrlen);
|
||||
sa6->sin6_family = AF_INET6;
|
||||
memmove(&sa6->sin6_addr, &repinfo->pktinfo.v6info.ipi6_addr,
|
||||
*localaddrlen);
|
||||
sizeof(struct in6_addr));
|
||||
sa6->sin6_port = repinfo->doq_srcport;
|
||||
#endif
|
||||
} else {
|
||||
@@ -3790,7 +3810,7 @@ doq_repinfo_retrieve_localaddr(struct comm_reply* repinfo,
|
||||
memset(sa, 0, *localaddrlen);
|
||||
sa->sin_family = AF_INET;
|
||||
memmove(&sa->sin_addr, &repinfo->pktinfo.v4info.ipi_addr,
|
||||
*localaddrlen);
|
||||
sizeof(struct in_addr));
|
||||
sa->sin_port = repinfo->doq_srcport;
|
||||
#elif defined(IP_RECVDSTADDR)
|
||||
struct sockaddr_in* sa = (struct sockaddr_in*)localaddr;
|
||||
@@ -3953,6 +3973,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",
|
||||
@@ -3982,7 +4007,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) {
|
||||
@@ -3992,6 +4018,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. */
|
||||
@@ -4018,24 +4049,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: "
|
||||
@@ -4080,6 +4143,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)) {
|
||||
@@ -4096,8 +4160,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 */
|
||||
@@ -4118,7 +4183,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 */
|
||||
@@ -4267,12 +4332,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;
|
||||
@@ -4335,8 +4399,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 */
|
||||
@@ -4394,8 +4457,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) {
|
||||
@@ -4464,6 +4527,29 @@ doq_stream_reset_cb(ngtcp2_conn* ATTR_UNUSED(conn), int64_t stream_id,
|
||||
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),
|
||||
@@ -4784,7 +4870,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);
|
||||
@@ -4838,6 +4924,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;
|
||||
|
||||
@@ -4892,6 +4979,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));
|
||||
@@ -5114,23 +5202,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. */
|
||||
@@ -5253,18 +5348,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;
|
||||
@@ -5352,7 +5446,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);
|
||||
|
||||
@@ -5405,7 +5498,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);
|
||||
@@ -5420,26 +5514,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;
|
||||
@@ -5477,7 +5565,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);
|
||||
@@ -5491,7 +5580,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;
|
||||
}
|
||||
|
||||
@@ -5568,32 +5657,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;
|
||||
@@ -5614,13 +5706,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.
|
||||
@@ -538,8 +540,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 +694,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 +801,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 +832,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 +850,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 +873,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 +891,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 */
|
||||
|
||||
+162
-86
@@ -56,6 +56,24 @@
|
||||
* with 16 bytes for an A record, a 64K packet has about 4000 max */
|
||||
#define LOCALZONE_RRSET_COUNT_MAX 4096
|
||||
|
||||
static const char* default_zones_reverse_array[] = {
|
||||
"127.in-addr.arpa.", /* reverse ip4 zone */
|
||||
"1.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.ip6.arpa.", /* reverse ip6 zone */
|
||||
0
|
||||
};
|
||||
const char** local_zones_default_reverse = default_zones_reverse_array;
|
||||
|
||||
static const char* default_zones_special_array[] = {
|
||||
"test.", /* RFC 6761 */
|
||||
"invalid.", /* RFC 6761 */
|
||||
"onion.", /* RFC 7686 */
|
||||
"home.arpa.", /* RFC 8375 */
|
||||
"resolver.arpa.", /* RFC 9462 */
|
||||
"service.arpa.", /* RFC 9665 */
|
||||
0
|
||||
};
|
||||
const char** local_zones_default_special = default_zones_special_array;
|
||||
|
||||
/** print all RRsets in local zone */
|
||||
static void
|
||||
local_zone_out(struct local_zone* z)
|
||||
@@ -368,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) {
|
||||
@@ -390,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;
|
||||
}
|
||||
|
||||
@@ -413,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;
|
||||
}
|
||||
@@ -428,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;
|
||||
}
|
||||
@@ -650,10 +676,12 @@ lz_enter_rr_str(struct local_zones* zones, const char* rr)
|
||||
}
|
||||
labs = dname_count_size_labels(rr_name, &len);
|
||||
lock_rw_rdlock(&zones->lock);
|
||||
z = local_zones_lookup(zones, rr_name, len, labs, rr_class, rr_type);
|
||||
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);
|
||||
@@ -834,7 +862,7 @@ lz_nodefault(struct config_file* cfg, const char* name)
|
||||
|
||||
for(p = cfg->local_zones_nodefault; p; p = p->next) {
|
||||
/* compare zone name, lowercase, compare without ending . */
|
||||
if(strncasecmp(p->str, name, len) == 0 &&
|
||||
if(strncasecmp(p->str, name, len) == 0 &&
|
||||
(strlen(p->str) == len || (strlen(p->str)==len+1 &&
|
||||
p->str[len] == '.')))
|
||||
return 1;
|
||||
@@ -842,6 +870,45 @@ lz_nodefault(struct config_file* cfg, const char* name)
|
||||
return 0;
|
||||
}
|
||||
|
||||
/** enter reverse default zone */
|
||||
static int
|
||||
add_reverse_default(struct local_zones* zones, struct config_file* cfg,
|
||||
const char* name)
|
||||
{
|
||||
struct local_zone* z;
|
||||
char str[1024]; /* known long enough */
|
||||
if(lz_exists(zones, name) || lz_nodefault(cfg, name))
|
||||
return 1; /* do not enter default content */
|
||||
if(!(z=lz_enter_zone(zones, name, "static", LDNS_RR_CLASS_IN)))
|
||||
return 0;
|
||||
snprintf(str, sizeof(str), "%s 10800 IN SOA localhost. "
|
||||
"nobody.invalid. 1 3600 1200 604800 10800", name);
|
||||
if(!lz_enter_rr_into_zone(z, str)) {
|
||||
lock_rw_unlock(&z->lock);
|
||||
return 0;
|
||||
}
|
||||
snprintf(str, sizeof(str), "%s 10800 IN NS localhost. ", name);
|
||||
if(!lz_enter_rr_into_zone(z, str)) {
|
||||
lock_rw_unlock(&z->lock);
|
||||
return 0;
|
||||
}
|
||||
if(strncasecmp("127.in-addr.arpa.", name, 17) == 0) {
|
||||
if(!lz_enter_rr_into_zone(z,
|
||||
"1.0.0.127.in-addr.arpa. 10800 IN PTR localhost.")) {
|
||||
lock_rw_unlock(&z->lock);
|
||||
return 0;
|
||||
}
|
||||
} else if(strncasecmp("1.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.ip6.arpa.", name, 73) == 0) {
|
||||
snprintf(str, sizeof(str), "%s 10800 IN PTR localhost.", name);
|
||||
if(!lz_enter_rr_into_zone(z, str)) {
|
||||
lock_rw_unlock(&z->lock);
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
lock_rw_unlock(&z->lock);
|
||||
return 1;
|
||||
}
|
||||
|
||||
/** enter (AS112) empty default zone */
|
||||
static int
|
||||
add_empty_default(struct local_zones* zones, struct config_file* cfg,
|
||||
@@ -902,72 +969,23 @@ int local_zone_enter_defaults(struct local_zones* zones, struct config_file* cfg
|
||||
}
|
||||
lock_rw_unlock(&z->lock);
|
||||
}
|
||||
/* reverse ip4 zone */
|
||||
if(!lz_exists(zones, "127.in-addr.arpa.") &&
|
||||
!lz_nodefault(cfg, "127.in-addr.arpa.")) {
|
||||
if(!(z=lz_enter_zone(zones, "127.in-addr.arpa.", "static",
|
||||
LDNS_RR_CLASS_IN)) ||
|
||||
!lz_enter_rr_into_zone(z,
|
||||
"127.in-addr.arpa. 10800 IN NS localhost.") ||
|
||||
!lz_enter_rr_into_zone(z,
|
||||
"127.in-addr.arpa. 10800 IN SOA localhost. "
|
||||
"nobody.invalid. 1 3600 1200 604800 10800") ||
|
||||
!lz_enter_rr_into_zone(z,
|
||||
"1.0.0.127.in-addr.arpa. 10800 IN PTR localhost.")) {
|
||||
|
||||
/* ip4 and ip6 reverse */
|
||||
for(zstr = local_zones_default_reverse; *zstr; zstr++) {
|
||||
if(!add_reverse_default(zones, cfg, *zstr)) {
|
||||
log_err("out of memory adding default zone");
|
||||
if(z) { lock_rw_unlock(&z->lock); }
|
||||
return 0;
|
||||
}
|
||||
lock_rw_unlock(&z->lock);
|
||||
}
|
||||
/* reverse ip6 zone */
|
||||
if(!lz_exists(zones, "1.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.ip6.arpa.") &&
|
||||
!lz_nodefault(cfg, "1.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.ip6.arpa.")) {
|
||||
if(!(z=lz_enter_zone(zones, "1.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.ip6.arpa.", "static",
|
||||
LDNS_RR_CLASS_IN)) ||
|
||||
!lz_enter_rr_into_zone(z,
|
||||
"1.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.ip6.arpa. 10800 IN NS localhost.") ||
|
||||
!lz_enter_rr_into_zone(z,
|
||||
"1.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.ip6.arpa. 10800 IN SOA localhost. "
|
||||
"nobody.invalid. 1 3600 1200 604800 10800") ||
|
||||
!lz_enter_rr_into_zone(z,
|
||||
"1.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.ip6.arpa. 10800 IN PTR localhost.")) {
|
||||
|
||||
/* special-use zones */
|
||||
for(zstr = local_zones_default_special; *zstr; zstr++) {
|
||||
if(!add_empty_default(zones, cfg, *zstr)) {
|
||||
log_err("out of memory adding default zone");
|
||||
if(z) { lock_rw_unlock(&z->lock); }
|
||||
return 0;
|
||||
}
|
||||
lock_rw_unlock(&z->lock);
|
||||
}
|
||||
/* home.arpa. zone (RFC 8375) */
|
||||
if(!add_empty_default(zones, cfg, "home.arpa.")) {
|
||||
log_err("out of memory adding default zone");
|
||||
return 0;
|
||||
}
|
||||
/* resolver.arpa. zone (RFC 9462) */
|
||||
if(!add_empty_default(zones, cfg, "resolver.arpa.")) {
|
||||
log_err("out of memory adding default zone");
|
||||
return 0;
|
||||
}
|
||||
/* service.arpa. zone (draft-ietf-dnssd-srp-25) */
|
||||
if(!add_empty_default(zones, cfg, "service.arpa.")) {
|
||||
log_err("out of memory adding default zone");
|
||||
return 0;
|
||||
}
|
||||
/* onion. zone (RFC 7686) */
|
||||
if(!add_empty_default(zones, cfg, "onion.")) {
|
||||
log_err("out of memory adding default zone");
|
||||
return 0;
|
||||
}
|
||||
/* test. zone (RFC 6761) */
|
||||
if(!add_empty_default(zones, cfg, "test.")) {
|
||||
log_err("out of memory adding default zone");
|
||||
return 0;
|
||||
}
|
||||
/* invalid. zone (RFC 6761) */
|
||||
if(!add_empty_default(zones, cfg, "invalid.")) {
|
||||
log_err("out of memory adding default zone");
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* block AS112 zones, unless asked not to */
|
||||
if(!cfg->unblock_lan_zones) {
|
||||
for(zstr = as112_zones; *zstr; zstr++) {
|
||||
@@ -1062,14 +1080,15 @@ lz_setup_implicit(struct local_zones* zones, struct config_file* cfg)
|
||||
labs = dname_count_size_labels(rr_name, &len);
|
||||
lock_rw_rdlock(&zones->lock);
|
||||
if(!local_zones_lookup(zones, rr_name, len, labs, rr_class,
|
||||
rr_type)) {
|
||||
rr_type, 1)) {
|
||||
/* Check if there is a zone that this could go
|
||||
* under but for different class; created zones are
|
||||
* always for LDNS_RR_CLASS_IN. Create the zone with
|
||||
* a different class but the same configured
|
||||
* local_zone_type. */
|
||||
struct local_zone* z = local_zones_lookup(zones,
|
||||
rr_name, len, labs, LDNS_RR_CLASS_IN, rr_type);
|
||||
rr_name, len, labs, LDNS_RR_CLASS_IN, rr_type,
|
||||
1);
|
||||
if(z) {
|
||||
uint8_t* name = memdup(z->name, z->namelen);
|
||||
size_t znamelen = z->namelen;
|
||||
@@ -1231,28 +1250,48 @@ local_zones_apply_cfg(struct local_zones* zones, struct config_file* cfg)
|
||||
|
||||
struct local_zone*
|
||||
local_zones_lookup(struct local_zones* zones,
|
||||
uint8_t* name, size_t len, int labs, uint16_t dclass, uint16_t dtype)
|
||||
uint8_t* name, size_t len, int labs, uint16_t dclass, uint16_t dtype,
|
||||
int foradd)
|
||||
{
|
||||
return local_zones_tags_lookup(zones, name, len, labs,
|
||||
dclass, dtype, NULL, 0, 1);
|
||||
dclass, dtype, NULL, 0, 1, foradd);
|
||||
}
|
||||
|
||||
struct local_zone*
|
||||
local_zones_tags_lookup(struct local_zones* zones,
|
||||
uint8_t* name, size_t len, int labs, uint16_t dclass, uint16_t dtype,
|
||||
uint8_t* taglist, size_t taglen, int ignoretags)
|
||||
uint8_t* taglist, size_t taglen, int ignoretags, int foradd)
|
||||
{
|
||||
rbnode_type* res = NULL;
|
||||
struct local_zone *result;
|
||||
struct local_zone key;
|
||||
int m;
|
||||
/* for type DS use a zone higher when on a zonecut */
|
||||
if(dtype == LDNS_RR_TYPE_DS && !dname_is_root(name)) {
|
||||
dname_remove_label(&name, &len);
|
||||
labs--;
|
||||
}
|
||||
key.node.key = &key;
|
||||
key.dclass = dclass;
|
||||
/* for type DS use a zone higher when on a zonecut */
|
||||
if(dtype == LDNS_RR_TYPE_DS && !dname_is_root(name)) {
|
||||
/* If this is at a zone cut, of a local-zone, and it is
|
||||
* of type always_refuse. Then also refuse the type DS
|
||||
* for it. That could make it DNSSEC bogus, but it is
|
||||
* REFUSED anyway. It stops CNAME type answers in the
|
||||
* type DS lookup. */
|
||||
key.name = name;
|
||||
key.namelen = len;
|
||||
key.namelabs = labs;
|
||||
/* For additions and removals, use the ordinary rule,
|
||||
* to remove a label for type DS to locate the parent zone.
|
||||
* That is where the DS RR needs to be put. */
|
||||
if(!foradd &&
|
||||
(result=(struct local_zone*)rbtree_search(
|
||||
&zones->ztree, &key)) != NULL &&
|
||||
result->type == local_zone_always_refuse) {
|
||||
/* The type DS does not go up one label. */
|
||||
return result;
|
||||
} else {
|
||||
dname_remove_label(&name, &len);
|
||||
labs--;
|
||||
}
|
||||
}
|
||||
key.name = name;
|
||||
key.namelen = len;
|
||||
key.namelabs = labs;
|
||||
@@ -1471,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;
|
||||
}
|
||||
@@ -1538,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;
|
||||
@@ -1573,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:
|
||||
@@ -1621,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
|
||||
@@ -1632,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);
|
||||
@@ -1698,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,
|
||||
@@ -1707,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,
|
||||
@@ -1863,7 +1924,7 @@ local_zones_answer(struct local_zones* zones, struct module_env* env,
|
||||
if(view->local_zones &&
|
||||
(z = local_zones_lookup(view->local_zones,
|
||||
qinfo->qname, qinfo->qname_len, labs,
|
||||
qinfo->qclass, qinfo->qtype))) {
|
||||
qinfo->qclass, qinfo->qtype, 0))) {
|
||||
lock_rw_rdlock(&z->lock);
|
||||
lzt = z->type;
|
||||
}
|
||||
@@ -1875,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;
|
||||
@@ -1897,7 +1961,7 @@ local_zones_answer(struct local_zones* zones, struct module_env* env,
|
||||
lock_rw_rdlock(&zones->lock);
|
||||
if(!(z = local_zones_tags_lookup(zones, qinfo->qname,
|
||||
qinfo->qname_len, labs, qinfo->qclass, qinfo->qtype,
|
||||
taglist, taglen, 0))) {
|
||||
taglist, taglen, 0, 0))) {
|
||||
lock_rw_unlock(&zones->lock);
|
||||
return 0;
|
||||
}
|
||||
@@ -1924,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
|
||||
@@ -1955,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";
|
||||
@@ -1991,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)
|
||||
@@ -2102,7 +2176,8 @@ local_zones_add_RR(struct local_zones* zones, const char* rr)
|
||||
/* could first try readlock then get writelock if zone does not exist,
|
||||
* but we do not add enough RRs (from multiple threads) to optimize */
|
||||
lock_rw_wrlock(&zones->lock);
|
||||
z = local_zones_lookup(zones, rr_name, len, labs, rr_class, rr_type);
|
||||
z = local_zones_lookup(zones, rr_name, len, labs, rr_class, rr_type,
|
||||
1);
|
||||
if(!z) {
|
||||
z = local_zones_add_zone(zones, rr_name, len, labs, rr_class,
|
||||
local_zone_transparent);
|
||||
@@ -2180,7 +2255,8 @@ void local_zones_del_data(struct local_zones* zones,
|
||||
|
||||
/* remove DS */
|
||||
lock_rw_rdlock(&zones->lock);
|
||||
z = local_zones_lookup(zones, name, len, labs, dclass, LDNS_RR_TYPE_DS);
|
||||
z = local_zones_lookup(zones, name, len, labs, dclass, LDNS_RR_TYPE_DS,
|
||||
1);
|
||||
if(z) {
|
||||
lock_rw_wrlock(&z->lock);
|
||||
d = local_zone_find_data(z, name, len, labs);
|
||||
@@ -2194,7 +2270,7 @@ void local_zones_del_data(struct local_zones* zones,
|
||||
|
||||
/* remove other types */
|
||||
lock_rw_rdlock(&zones->lock);
|
||||
z = local_zones_lookup(zones, name, len, labs, dclass, 0);
|
||||
z = local_zones_lookup(zones, name, len, labs, dclass, 0, 1);
|
||||
if(!z) {
|
||||
/* no such zone, we're done */
|
||||
lock_rw_unlock(&zones->lock);
|
||||
|
||||
+17
-3
@@ -57,6 +57,9 @@ struct sldns_buffer;
|
||||
struct comm_reply;
|
||||
struct config_strlist;
|
||||
|
||||
extern const char** local_zones_default_special;
|
||||
extern const char** local_zones_default_reverse;
|
||||
|
||||
/**
|
||||
* Local zone type
|
||||
* This type determines processing for queries that did not match
|
||||
@@ -90,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 */
|
||||
@@ -262,11 +271,13 @@ void local_zone_delete(struct local_zone* z);
|
||||
* @param taglen: length of taglist.
|
||||
* @param ignoretags: lookup zone by name and class, regardless the
|
||||
* local-zone's tags.
|
||||
* @param foradd: if the lookup is for addition or removal of the type.
|
||||
* Used for type DS. The lookup for answers turns this off.
|
||||
* @return closest local_zone or NULL if no covering zone is found.
|
||||
*/
|
||||
struct local_zone* local_zones_tags_lookup(struct local_zones* zones,
|
||||
uint8_t* name, size_t len, int labs, uint16_t dclass, uint16_t dtype,
|
||||
uint8_t* taglist, size_t taglen, int ignoretags);
|
||||
uint8_t* taglist, size_t taglen, int ignoretags, int foradd);
|
||||
|
||||
/**
|
||||
* Lookup zone that contains the given name, class.
|
||||
@@ -278,10 +289,13 @@ struct local_zone* local_zones_tags_lookup(struct local_zones* zones,
|
||||
* @param dclass: class to lookup.
|
||||
* @param dtype: type of the record, if type DS then a zone higher up is found
|
||||
* pass 0 to just plain find a zone for a name.
|
||||
* @param foradd: if the lookup is for addition or removal of the type.
|
||||
* Used for type DS. The lookup for answers turns this off.
|
||||
* @return closest local_zone or NULL if no covering zone is found.
|
||||
*/
|
||||
struct local_zone* local_zones_lookup(struct local_zones* zones,
|
||||
uint8_t* name, size_t len, int labs, uint16_t dclass, uint16_t dtype);
|
||||
uint8_t* name, size_t len, int labs, uint16_t dclass, uint16_t dtype,
|
||||
int foradd);
|
||||
|
||||
/**
|
||||
* Debug helper. Print all zones
|
||||
@@ -565,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,
|
||||
|
||||
+203
-67
@@ -297,12 +297,14 @@ int mesh_make_new_space(struct mesh_area* mesh, sldns_buffer* qbuf)
|
||||
if(mesh->num_reply_states < mesh->max_reply_states)
|
||||
return 1;
|
||||
/* try to kick out a jostle-list item */
|
||||
if(m && m->reply_list && m->list_select == mesh_jostle_list) {
|
||||
if(m && m->list_select == mesh_jostle_list) {
|
||||
/* how old is it? */
|
||||
struct timeval age;
|
||||
timeval_subtract(&age, mesh->env->now_tv,
|
||||
&m->reply_list->start_time);
|
||||
if(timeval_smaller(&mesh->jostle_max, &age)) {
|
||||
if(m->has_first_reply_time)
|
||||
timeval_subtract(&age, mesh->env->now_tv,
|
||||
&m->first_reply_time);
|
||||
if(!m->has_first_reply_time ||
|
||||
timeval_smaller(&mesh->jostle_max, &age)) {
|
||||
/* its a goner */
|
||||
log_nametypeclass(VERB_ALGO, "query jostled out to "
|
||||
"make space for a new one",
|
||||
@@ -422,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,
|
||||
@@ -431,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;
|
||||
@@ -465,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;
|
||||
@@ -478,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;
|
||||
@@ -538,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)) {
|
||||
@@ -567,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 */
|
||||
@@ -603,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;
|
||||
@@ -612,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);
|
||||
@@ -621,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);
|
||||
@@ -666,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;
|
||||
@@ -683,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;
|
||||
@@ -698,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;
|
||||
@@ -901,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)
|
||||
@@ -946,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
|
||||
@@ -969,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;
|
||||
}
|
||||
@@ -1036,6 +1074,7 @@ mesh_state_create(struct module_env* env, struct query_info* qinfo,
|
||||
mstate->s.no_cache_store = 0;
|
||||
mstate->s.need_refetch = 0;
|
||||
mstate->s.was_ratelimited = 0;
|
||||
mstate->s.error_response_cache = 0;
|
||||
mstate->s.qstarttime = *env->now;
|
||||
|
||||
/* init modules */
|
||||
@@ -1082,8 +1121,6 @@ mesh_state_cleanup(struct mesh_state* mstate)
|
||||
for(; rep; rep=rep->next) {
|
||||
infra_wait_limit_dec(mesh->env->infra_cache,
|
||||
&rep->query_reply, mesh->env->cfg);
|
||||
if(rep->query_reply.c->use_h2)
|
||||
http2_stream_remove_mesh_state(rep->h2_stream);
|
||||
comm_point_drop_reply(&rep->query_reply);
|
||||
log_assert(mesh->num_reply_addrs > 0);
|
||||
mesh->num_reply_addrs--;
|
||||
@@ -1220,6 +1257,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
|
||||
@@ -1475,6 +1515,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:
|
||||
@@ -1629,9 +1673,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;
|
||||
@@ -1738,7 +1782,8 @@ 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) {
|
||||
@@ -1768,6 +1813,8 @@ void mesh_query_done(struct mesh_state* mstate)
|
||||
mstate->reply_list = NULL;
|
||||
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);
|
||||
@@ -1805,6 +1852,8 @@ void mesh_query_done(struct mesh_state* mstate)
|
||||
mstate->reply_list = NULL;
|
||||
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;
|
||||
@@ -1917,6 +1966,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)
|
||||
{
|
||||
@@ -1938,7 +2006,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));
|
||||
@@ -1962,13 +2030,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));
|
||||
@@ -1988,6 +2057,10 @@ int mesh_state_add_reply(struct mesh_state* s, struct edns_data* edns,
|
||||
r->qid = qid;
|
||||
r->qflags = qflags;
|
||||
r->start_time = *s->s.env->now_tv;
|
||||
if(s->reply_list == NULL && !s->has_first_reply_time) {
|
||||
s->first_reply_time = r->start_time;
|
||||
s->has_first_reply_time = 1;
|
||||
}
|
||||
r->next = s->reply_list;
|
||||
r->qname = regional_alloc_init(s->s.region, qinfo->qname,
|
||||
s->s.qinfo.qname_len);
|
||||
@@ -1996,6 +2069,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
|
||||
@@ -2043,6 +2118,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;
|
||||
}
|
||||
|
||||
@@ -2200,8 +2276,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));
|
||||
@@ -2353,7 +2450,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;
|
||||
@@ -2361,7 +2459,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;
|
||||
@@ -2370,6 +2470,14 @@ void mesh_state_remove_reply(struct mesh_area* mesh, struct mesh_state* m,
|
||||
mesh->num_reply_addrs--;
|
||||
infra_wait_limit_dec(mesh->env->infra_cache,
|
||||
&n->query_reply, mesh->env->cfg);
|
||||
/* We may be removing more than one http2 stream (they
|
||||
* 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;
|
||||
@@ -2410,9 +2518,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;
|
||||
@@ -2477,12 +2586,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) {
|
||||
@@ -2493,6 +2605,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
|
||||
@@ -2519,9 +2632,10 @@ mesh_serve_expired_callback(void* arg)
|
||||
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 &&
|
||||
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 */
|
||||
@@ -2537,10 +2651,15 @@ mesh_serve_expired_callback(void* arg)
|
||||
mstate->reply_list = NULL;
|
||||
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++;
|
||||
@@ -2637,13 +2756,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--;
|
||||
|
||||
+50
-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
|
||||
@@ -191,6 +198,12 @@ struct mesh_state {
|
||||
struct module_qstate s;
|
||||
/** the list of replies to clients for the results */
|
||||
struct mesh_reply* reply_list;
|
||||
/** if it has a first reply time */
|
||||
int has_first_reply_time;
|
||||
/** wall-clock time the first client reply was attached;
|
||||
* used by mesh_make_new_space() so duplicate retransmits
|
||||
* cannot reset jostle aging. */
|
||||
struct timeval first_reply_time;
|
||||
/** the list of callbacks for the results */
|
||||
struct mesh_cb* cb_list;
|
||||
/** set of superstates (that want this state's result)
|
||||
@@ -336,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.
|
||||
@@ -537,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.
|
||||
@@ -556,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.
|
||||
@@ -572,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
|
||||
@@ -677,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.
|
||||
@@ -726,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 */
|
||||
|
||||
+439
-79
@@ -160,6 +160,19 @@ reuse_cmp_addrportssl(const void* key1, const void* key2)
|
||||
return 1;
|
||||
if(!r1->is_ssl && r2->is_ssl)
|
||||
return -1;
|
||||
|
||||
/* compare tls_auth_name if SSL-enabled */
|
||||
if(r1->is_ssl) {
|
||||
if(r1->tls_auth_name && !r2->tls_auth_name)
|
||||
return 1;
|
||||
if(!r1->tls_auth_name && r2->tls_auth_name)
|
||||
return -1;
|
||||
if(r1->tls_auth_name && r2->tls_auth_name) {
|
||||
r = strcmp(r1->tls_auth_name, r2->tls_auth_name);
|
||||
if(r != 0)
|
||||
return r;
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -195,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);
|
||||
@@ -531,7 +545,7 @@ reuse_tcp_insert(struct outside_network* outnet, struct pending_tcp* pend_tcp)
|
||||
/** find reuse tcp stream to destination for query, or NULL if none */
|
||||
static struct reuse_tcp*
|
||||
reuse_tcp_find(struct outside_network* outnet, struct sockaddr_storage* addr,
|
||||
socklen_t addrlen, int use_ssl)
|
||||
socklen_t addrlen, int use_ssl, char* tls_auth_name)
|
||||
{
|
||||
struct waiting_tcp key_w;
|
||||
struct pending_tcp key_p;
|
||||
@@ -545,8 +559,10 @@ reuse_tcp_find(struct outside_network* outnet, struct sockaddr_storage* addr,
|
||||
key_p.c = &c;
|
||||
key_p.reuse.pending = &key_p;
|
||||
key_p.reuse.node.key = &key_p.reuse;
|
||||
if(use_ssl)
|
||||
if(use_ssl) {
|
||||
key_p.reuse.is_ssl = 1;
|
||||
key_p.reuse.tls_auth_name = tls_auth_name;
|
||||
}
|
||||
if(addrlen > (socklen_t)sizeof(key_p.reuse.addr))
|
||||
return NULL;
|
||||
memmove(&key_p.reuse.addr, addr, addrlen);
|
||||
@@ -646,6 +662,7 @@ static int
|
||||
outnet_tcp_take_into_use(struct waiting_tcp* w)
|
||||
{
|
||||
struct pending_tcp* pend = w->outnet->tcp_free;
|
||||
char* tls_auth_name = NULL;
|
||||
int s;
|
||||
log_assert(pend);
|
||||
log_assert(w->pkt);
|
||||
@@ -746,7 +763,22 @@ outnet_tcp_take_into_use(struct waiting_tcp* w)
|
||||
comm_point_tcp_win_bio_cb(pend->c, pend->c->ssl);
|
||||
#endif
|
||||
pend->c->ssl_shake_state = comm_ssl_shake_write;
|
||||
if(!set_auth_name_on_ssl(pend->c->ssl, w->tls_auth_name,
|
||||
if(w->tls_auth_name) {
|
||||
/* strdup the auth name, while not linked the list yet,
|
||||
* in case of failure, easy cleanup. */
|
||||
tls_auth_name = strdup(w->tls_auth_name);
|
||||
if(!tls_auth_name) {
|
||||
log_err("out of memory: alloc tls auth name");
|
||||
pend->c->fd = s;
|
||||
#ifdef HAVE_SSL
|
||||
SSL_free(pend->c->ssl);
|
||||
#endif
|
||||
pend->c->ssl = NULL;
|
||||
comm_point_close(pend->c);
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
if(!set_auth_name_on_ssl(pend->c->ssl, tls_auth_name,
|
||||
w->outnet->tls_use_sni)) {
|
||||
pend->c->fd = s;
|
||||
#ifdef HAVE_SSL
|
||||
@@ -754,6 +786,7 @@ outnet_tcp_take_into_use(struct waiting_tcp* w)
|
||||
#endif
|
||||
pend->c->ssl = NULL;
|
||||
comm_point_close(pend->c);
|
||||
free(tls_auth_name);
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
@@ -778,9 +811,20 @@ outnet_tcp_take_into_use(struct waiting_tcp* w)
|
||||
if(pend->reuse.node.key)
|
||||
reuse_tcp_remove_tree_list(w->outnet, &pend->reuse);
|
||||
|
||||
if(pend->c->ssl)
|
||||
if(pend->c->ssl) {
|
||||
pend->reuse.is_ssl = 1;
|
||||
else pend->reuse.is_ssl = 0;
|
||||
if(pend->reuse.tls_auth_name)
|
||||
free(pend->reuse.tls_auth_name);
|
||||
pend->reuse.tls_auth_name = tls_auth_name;
|
||||
tls_auth_name = NULL;
|
||||
} else {
|
||||
pend->reuse.is_ssl = 0;
|
||||
if(pend->reuse.tls_auth_name)
|
||||
free(pend->reuse.tls_auth_name);
|
||||
pend->reuse.tls_auth_name = NULL;
|
||||
}
|
||||
/* free tls auth name if nonNULL */
|
||||
free(tls_auth_name);
|
||||
/* insert in reuse by address tree if not already inserted there */
|
||||
(void)reuse_tcp_insert(w->outnet, pend);
|
||||
reuse_tree_by_id_insert(&pend->reuse, w);
|
||||
@@ -969,7 +1013,7 @@ use_free_buffer(struct outside_network* outnet)
|
||||
(!outnet->tcp_reuse_first && !outnet->tcp_reuse_last) ||
|
||||
(outnet->tcp_reuse_first && outnet->tcp_reuse_last));
|
||||
reuse = reuse_tcp_find(outnet, &w->addr, w->addrlen,
|
||||
w->ssl_upstream);
|
||||
w->ssl_upstream, w->tls_auth_name);
|
||||
/* re-select an ID when moving to a new TCP buffer */
|
||||
w->id = tcp_select_id(outnet, reuse);
|
||||
LDNS_ID_SET(w->pkt, w->id);
|
||||
@@ -1198,6 +1242,10 @@ decommission_pending_tcp(struct outside_network* outnet,
|
||||
/* needs unlink from the reuse tree to get deleted */
|
||||
reuse_tcp_remove_tree_list(outnet, &pend->reuse);
|
||||
}
|
||||
if(pend->reuse.tls_auth_name) {
|
||||
free(pend->reuse.tls_auth_name);
|
||||
pend->reuse.tls_auth_name = NULL;
|
||||
}
|
||||
/* free SSL structure after remove from outnet tcp reuse tree,
|
||||
* because the c->ssl null or not is used for sorting in the tree */
|
||||
if(pend->c->ssl) {
|
||||
@@ -1433,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];
|
||||
@@ -1647,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,
|
||||
@@ -1673,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));
|
||||
@@ -1713,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;
|
||||
@@ -1723,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
|
||||
@@ -1784,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;
|
||||
@@ -1801,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;
|
||||
@@ -1810,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;
|
||||
@@ -1888,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);
|
||||
@@ -1904,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);
|
||||
@@ -1922,6 +1978,10 @@ outside_network_delete(struct outside_network* outnet)
|
||||
* the tcp conn is working on */
|
||||
decommission_pending_tcp(outnet, pend);
|
||||
}
|
||||
if(pend->reuse.tls_auth_name) {
|
||||
free(pend->reuse.tls_auth_name);
|
||||
pend->reuse.tls_auth_name = NULL;
|
||||
}
|
||||
comm_point_delete(outnet->tcp_conns[i]->c);
|
||||
free(outnet->tcp_conns[i]);
|
||||
outnet->tcp_conns[i] = NULL;
|
||||
@@ -2112,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) {
|
||||
@@ -2126,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) {
|
||||
@@ -2173,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;
|
||||
}
|
||||
}
|
||||
@@ -2190,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) {
|
||||
@@ -2447,7 +2513,7 @@ pending_tcp_query(struct serviced_query* sq, sldns_buffer* packet,
|
||||
/* find out if a reused stream to the target exists */
|
||||
/* if so, take it into use */
|
||||
reuse = reuse_tcp_find(sq->outnet, &sq->addr, sq->addrlen,
|
||||
sq->ssl_upstream);
|
||||
sq->ssl_upstream, sq->tls_auth_name);
|
||||
if(reuse) {
|
||||
log_reuse_tcp(VERB_CLIENT, "pending_tcp_query: found reuse", reuse);
|
||||
log_assert(reuse->pending);
|
||||
@@ -2489,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;
|
||||
@@ -3287,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);
|
||||
@@ -3426,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;
|
||||
@@ -3498,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,
|
||||
@@ -3579,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;
|
||||
@@ -3614,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;
|
||||
@@ -3638,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;
|
||||
}
|
||||
@@ -3690,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
|
||||
@@ -3819,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");
|
||||
@@ -3868,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);
|
||||
@@ -3960,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
|
||||
}
|
||||
|
||||
+104
-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.
|
||||
*/
|
||||
@@ -264,6 +302,9 @@ struct reuse_tcp {
|
||||
socklen_t addrlen;
|
||||
/** also key for tcp_reuse tree, if ssl is used */
|
||||
int is_ssl;
|
||||
/** If is_ssl is enabled, tls_auth_name is part of the key for
|
||||
* tcp_reuse tree. If the string is NULL, it without a tls_auth_name */
|
||||
char* tls_auth_name;
|
||||
/** lru chain, so that the oldest can be removed to get a new
|
||||
* connection when all are in (re)use. oldest is last in list.
|
||||
* The lru only contains empty connections waiting for reuse,
|
||||
@@ -416,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;
|
||||
@@ -497,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 */
|
||||
@@ -548,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.
|
||||
@@ -564,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.
|
||||
@@ -657,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.
|
||||
*/
|
||||
@@ -666,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.
|
||||
@@ -816,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);
|
||||
|
||||
+40
-21
@@ -153,6 +153,7 @@ rpz_type_ignored(uint16_t rr_type)
|
||||
case LDNS_RR_TYPE_SOA:
|
||||
case LDNS_RR_TYPE_NS:
|
||||
case LDNS_RR_TYPE_DNAME:
|
||||
case LDNS_RR_TYPE_ZONEMD:
|
||||
/* all DNSSEC-related RRs must be ignored */
|
||||
case LDNS_RR_TYPE_DNSKEY:
|
||||
case LDNS_RR_TYPE_DS:
|
||||
@@ -720,13 +721,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);
|
||||
}
|
||||
@@ -804,8 +814,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);
|
||||
@@ -903,8 +914,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*)
|
||||
@@ -913,8 +924,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) {
|
||||
@@ -953,12 +962,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
|
||||
@@ -981,7 +996,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)) {
|
||||
@@ -991,6 +1005,7 @@ rpz_clientip_insert_trigger_rr(struct clientip_synthesized_rrset* set, struct so
|
||||
}
|
||||
|
||||
}
|
||||
node->action = a;
|
||||
|
||||
lock_rw_unlock(&node->lock);
|
||||
|
||||
@@ -1976,8 +1991,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;
|
||||
@@ -2007,8 +2023,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;
|
||||
@@ -2468,6 +2485,7 @@ rpz_callback_from_iterator_module(struct module_qstate* ms, struct iter_qstate*
|
||||
{
|
||||
struct auth_zones* az;
|
||||
struct auth_zone* a;
|
||||
struct dns_msg* ret = NULL;
|
||||
struct clientip_synthesized_rr* raddr = NULL;
|
||||
struct rpz* r = NULL;
|
||||
struct local_zone* z = NULL;
|
||||
@@ -2511,13 +2529,11 @@ rpz_callback_from_iterator_module(struct module_qstate* ms, struct iter_qstate*
|
||||
z = rpz_delegation_point_zone_lookup(is->dp, r->nsdname_zones,
|
||||
is->qchase.qclass, &match);
|
||||
if(z != NULL) {
|
||||
lock_rw_unlock(&a->lock);
|
||||
break;
|
||||
}
|
||||
|
||||
raddr = rpz_delegation_point_ipbased_trigger_lookup(r, is);
|
||||
if(raddr != NULL) {
|
||||
lock_rw_unlock(&a->lock);
|
||||
break;
|
||||
}
|
||||
lock_rw_unlock(&a->lock);
|
||||
@@ -2532,9 +2548,12 @@ rpz_callback_from_iterator_module(struct module_qstate* ms, struct iter_qstate*
|
||||
if(z) {
|
||||
lock_rw_unlock(&z->lock);
|
||||
}
|
||||
return rpz_apply_nsip_trigger(ms, &is->qchase, r, raddr, a);
|
||||
ret = rpz_apply_nsip_trigger(ms, &is->qchase, r, raddr, a);
|
||||
} else {
|
||||
ret = rpz_apply_nsdname_trigger(ms, &is->qchase, r, z, &match, a);
|
||||
}
|
||||
return rpz_apply_nsdname_trigger(ms, &is->qchase, r, z, &match, a);
|
||||
lock_rw_unlock(&a->lock);
|
||||
return ret;
|
||||
}
|
||||
|
||||
struct dns_msg* rpz_callback_from_iterator_cname(struct module_qstate* ms,
|
||||
|
||||
-1
Submodule simdzone deleted from eca67807d0
+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;
|
||||
}
|
||||
|
||||
+6
-4
@@ -842,7 +842,8 @@ rrinternal_parse_rdata(sldns_buffer* strbuf, char* token, size_t token_len,
|
||||
sldns_write_uint16(rr+dname_len+8, (uint16_t)(rr_cur_len-dname_len-10));
|
||||
*rr_len = rr_cur_len;
|
||||
/* SVCB/HTTPS handling */
|
||||
if (rr_type == LDNS_RR_TYPE_SVCB || rr_type == LDNS_RR_TYPE_HTTPS) {
|
||||
if ((rr_type == LDNS_RR_TYPE_SVCB || rr_type == LDNS_RR_TYPE_HTTPS)
|
||||
&& !was_unknown_rr_format) {
|
||||
size_t rdata_len = rr_cur_len - dname_len - 10;
|
||||
uint8_t *rdata = rr+dname_len + 10;
|
||||
|
||||
@@ -1201,7 +1202,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 +1257,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 +1318,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 +1411,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;
|
||||
}
|
||||
|
||||
+175
-13
@@ -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
|
||||
@@ -2430,12 +2584,20 @@ int main(int argc, char* argv[])
|
||||
#else
|
||||
OPENSSL_init_crypto(OPENSSL_INIT_ADD_ALL_CIPHERS
|
||||
| OPENSSL_INIT_ADD_ALL_DIGESTS
|
||||
| OPENSSL_INIT_LOAD_CRYPTO_STRINGS, NULL);
|
||||
| OPENSSL_INIT_LOAD_CRYPTO_STRINGS
|
||||
# if defined(OPENSSL_INIT_NO_LOAD_CONFIG) && defined(UB_ON_WINDOWS)
|
||||
| OPENSSL_INIT_NO_LOAD_CONFIG
|
||||
# endif
|
||||
, NULL);
|
||||
#endif
|
||||
#if OPENSSL_VERSION_NUMBER < 0x10100000 || !defined(HAVE_OPENSSL_INIT_SSL)
|
||||
(void)SSL_library_init();
|
||||
#else
|
||||
(void)OPENSSL_init_ssl(OPENSSL_INIT_LOAD_SSL_STRINGS, NULL);
|
||||
(void)OPENSSL_init_ssl(OPENSSL_INIT_LOAD_SSL_STRINGS
|
||||
# if defined(OPENSSL_INIT_NO_LOAD_CONFIG) && defined(UB_ON_WINDOWS)
|
||||
| OPENSSL_INIT_NO_LOAD_CONFIG
|
||||
# endif
|
||||
, NULL);
|
||||
#endif
|
||||
|
||||
if(dolist) do_list_builtin();
|
||||
|
||||
@@ -44,6 +44,7 @@
|
||||
|
||||
#include "config.h"
|
||||
#include <ctype.h>
|
||||
#include "util/as112.h"
|
||||
#include "util/log.h"
|
||||
#include "util/config_file.h"
|
||||
#include "util/module.h"
|
||||
@@ -72,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
|
||||
@@ -188,11 +192,56 @@ donotquerylocalhostcheck(struct config_file* cfg)
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
nodefaultzonescheck(struct config_file* cfg)
|
||||
{
|
||||
struct config_strlist* d;
|
||||
const char** zstr;
|
||||
size_t len;
|
||||
|
||||
#define COMPARE_ZONE_NAME(confname, builtname, len) \
|
||||
(strncasecmp(confname, builtname, (len)) == 0 && \
|
||||
(strlen(confname) == (len) || \
|
||||
(strlen(confname) == (len) + 1 \
|
||||
&& confname[(len)] == '.')))
|
||||
|
||||
for(d = cfg->local_zones_nodefault; d; d = d->next) {
|
||||
if(!cfg->unblock_lan_zones) {
|
||||
for(zstr = as112_zones; *zstr; zstr++) {
|
||||
len = strlen(*zstr) - 1; /* trailing '.' */
|
||||
if(COMPARE_ZONE_NAME(d->str, *zstr, len))
|
||||
goto default_continue;
|
||||
}
|
||||
}
|
||||
for(zstr = local_zones_default_special; *zstr; zstr++) {
|
||||
len = strlen(*zstr) - 1; /* trailing '.' */
|
||||
if(COMPARE_ZONE_NAME(d->str, *zstr, len))
|
||||
goto default_continue;
|
||||
}
|
||||
for(zstr = local_zones_default_reverse; *zstr; zstr++) {
|
||||
len = strlen(*zstr) - 1; /* trailing '.' */
|
||||
if(COMPARE_ZONE_NAME(d->str, *zstr, len))
|
||||
goto default_continue;
|
||||
}
|
||||
if(COMPARE_ZONE_NAME(d->str, "localhost.", 10 - 1))
|
||||
goto default_continue;
|
||||
fprintf(stderr, "unbound-checkconf: warning: local-zone: '%s' "
|
||||
"is configured as 'nodefault' but there is no such "
|
||||
"default local-zone. Check the unbound.conf "
|
||||
"documentation for default configured local-zones.\n",
|
||||
d->str);
|
||||
default_continue:
|
||||
; /* statement to jump to, for older gcc. */
|
||||
}
|
||||
#undef COMPARE_ZONE_NAME
|
||||
}
|
||||
|
||||
/** check localzones */
|
||||
static void
|
||||
localzonechecks(struct config_file* cfg)
|
||||
{
|
||||
struct local_zones* zs;
|
||||
nodefaultzonescheck(cfg);
|
||||
if(!(zs = local_zones_create()))
|
||||
fatal_exit("out of memory");
|
||||
if(!local_zones_apply_cfg(zs, cfg))
|
||||
@@ -682,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)
|
||||
@@ -776,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;
|
||||
|
||||
@@ -1052,12 +1052,20 @@ int main(int argc, char* argv[])
|
||||
#else
|
||||
OPENSSL_init_crypto(OPENSSL_INIT_ADD_ALL_CIPHERS
|
||||
| OPENSSL_INIT_ADD_ALL_DIGESTS
|
||||
| OPENSSL_INIT_LOAD_CRYPTO_STRINGS, NULL);
|
||||
| OPENSSL_INIT_LOAD_CRYPTO_STRINGS
|
||||
# if defined(OPENSSL_INIT_NO_LOAD_CONFIG) && defined(UB_ON_WINDOWS)
|
||||
| OPENSSL_INIT_NO_LOAD_CONFIG
|
||||
# endif
|
||||
, NULL);
|
||||
#endif
|
||||
#if OPENSSL_VERSION_NUMBER < 0x10100000 || !defined(HAVE_OPENSSL_INIT_SSL)
|
||||
(void)SSL_library_init();
|
||||
#else
|
||||
(void)OPENSSL_init_ssl(OPENSSL_INIT_LOAD_SSL_STRINGS, NULL);
|
||||
(void)OPENSSL_init_ssl(OPENSSL_INIT_LOAD_SSL_STRINGS
|
||||
# if defined(OPENSSL_INIT_NO_LOAD_CONFIG) && defined(UB_ON_WINDOWS)
|
||||
| OPENSSL_INIT_NO_LOAD_CONFIG
|
||||
# endif
|
||||
, NULL);
|
||||
#endif
|
||||
|
||||
if(!RAND_status()) {
|
||||
|
||||
+10
-2
@@ -521,12 +521,20 @@ int main(int argc, char* argv[])
|
||||
#else
|
||||
OPENSSL_init_crypto(OPENSSL_INIT_ADD_ALL_CIPHERS
|
||||
| OPENSSL_INIT_ADD_ALL_DIGESTS
|
||||
| OPENSSL_INIT_LOAD_CRYPTO_STRINGS, NULL);
|
||||
| OPENSSL_INIT_LOAD_CRYPTO_STRINGS
|
||||
# if defined(OPENSSL_INIT_NO_LOAD_CONFIG) && defined(UB_ON_WINDOWS)
|
||||
| OPENSSL_INIT_NO_LOAD_CONFIG
|
||||
# endif
|
||||
, NULL);
|
||||
#endif
|
||||
#if OPENSSL_VERSION_NUMBER < 0x10100000 || !defined(HAVE_OPENSSL_INIT_SSL)
|
||||
(void)SSL_library_init();
|
||||
#else
|
||||
(void)OPENSSL_init_ssl(OPENSSL_INIT_LOAD_SSL_STRINGS, NULL);
|
||||
(void)OPENSSL_init_ssl(OPENSSL_INIT_LOAD_SSL_STRINGS
|
||||
# if defined(OPENSSL_INIT_NO_LOAD_CONFIG) && defined(UB_ON_WINDOWS)
|
||||
| OPENSSL_INIT_NO_LOAD_CONFIG
|
||||
# endif
|
||||
, NULL);
|
||||
#endif
|
||||
#endif /* HAVE_SSL */
|
||||
#ifdef HAVE_NSS
|
||||
|
||||
@@ -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;
|
||||
|
||||
+10
-2
@@ -488,12 +488,20 @@ int main(int argc, char** argv)
|
||||
#else
|
||||
OPENSSL_init_crypto(OPENSSL_INIT_ADD_ALL_CIPHERS
|
||||
| OPENSSL_INIT_ADD_ALL_DIGESTS
|
||||
| OPENSSL_INIT_LOAD_CRYPTO_STRINGS, NULL);
|
||||
| OPENSSL_INIT_LOAD_CRYPTO_STRINGS
|
||||
# if defined(OPENSSL_INIT_NO_LOAD_CONFIG) && defined(UB_ON_WINDOWS)
|
||||
| OPENSSL_INIT_NO_LOAD_CONFIG
|
||||
# endif
|
||||
, NULL);
|
||||
#endif
|
||||
#if OPENSSL_VERSION_NUMBER < 0x10100000 || !defined(HAVE_OPENSSL_INIT_SSL)
|
||||
(void)SSL_library_init();
|
||||
#else
|
||||
(void)OPENSSL_init_ssl(OPENSSL_INIT_LOAD_SSL_STRINGS, NULL);
|
||||
(void)OPENSSL_init_ssl(OPENSSL_INIT_LOAD_SSL_STRINGS
|
||||
# if defined(OPENSSL_INIT_NO_LOAD_CONFIG) && defined(UB_ON_WINDOWS)
|
||||
| OPENSSL_INIT_NO_LOAD_CONFIG
|
||||
# endif
|
||||
, NULL);
|
||||
#endif
|
||||
#endif /* HAVE_SSL */
|
||||
|
||||
|
||||
@@ -360,6 +360,7 @@ typedef pthread_key_t ub_thread_key_type;
|
||||
#define ub_thread_key_create(key, f) LOCKRET(pthread_key_create(key, f))
|
||||
#define ub_thread_key_set(key, v) LOCKRET(pthread_setspecific(key, v))
|
||||
#define ub_thread_key_get(key) pthread_getspecific(key)
|
||||
#define ub_thread_setname(thread, name) /* nop */
|
||||
|
||||
#endif /* USE_THREAD_DEBUG */
|
||||
#endif /* TESTCODE_CHECK_LOCKS_H */
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user