mirror of
https://github.com/NLnetLabs/unbound.git
synced 2026-08-17 21:25:50 +02:00
Compare commits
359
Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
2ffc17e826 | ||
|
|
3af4e44646 | ||
|
|
c3dd6a2dbd | ||
|
|
8fca3e7c5b | ||
|
|
8947c2c764 | ||
|
|
b1e3319a11 | ||
|
|
d52f501d90 | ||
|
|
7083d58c6b | ||
|
|
3adb9c8f92 | ||
|
|
51425b2388 | ||
|
|
d43760a8cd | ||
|
|
ea3e327006 | ||
|
|
be09350eca | ||
|
|
169acfc546 | ||
|
|
bed7cc2a90 | ||
|
|
02f4446833 | ||
|
|
c8a2289542 | ||
|
|
b53d90053e | ||
|
|
978b0696d3 | ||
|
|
ec5f86b4eb | ||
|
|
ec2f45c6fd | ||
|
|
6b319c97ee | ||
|
|
6eb3992c9e | ||
|
|
94a94fd8c8 | ||
|
|
36f9d1a2a9 | ||
|
|
d3a2264272 | ||
|
|
92b6c2a7b9 | ||
|
|
a335e601e4 | ||
|
|
a19009df1d | ||
|
|
96f8a94c19 | ||
|
|
2fe4e2ec3e | ||
|
|
e54928a628 | ||
|
|
538434186e | ||
|
|
65e7253d19 | ||
|
|
03ac902296 | ||
|
|
97ad1df343 | ||
|
|
2279cde8f7 | ||
|
|
ff653a7ef8 | ||
|
|
fd11cd9182 | ||
|
|
3953f827fb | ||
|
|
7fbc061846 | ||
|
|
70f73a33b3 | ||
|
|
b67fbb69e7 | ||
|
|
902c79608c | ||
|
|
08050dc939 | ||
|
|
9603924bb4 | ||
|
|
4c2da2b979 | ||
|
|
1974732d19 | ||
|
|
3cad5818a1 | ||
|
|
ad12109191 | ||
|
|
f611220eb8 | ||
|
|
86fe9cbce5 | ||
|
|
ac609fcbfc | ||
|
|
486985fbdf | ||
|
|
caab100207 | ||
|
|
4b30e88eec | ||
|
|
b6c7ea563f | ||
|
|
910d7cf446 | ||
|
|
cd485f2036 | ||
|
|
8ff1baf585 | ||
|
|
5fc4673901 | ||
|
|
faf3d358dc | ||
|
|
f5a2160ba3 | ||
|
|
0c0c36f015 | ||
|
|
47956de897 | ||
|
|
b30c869a59 | ||
|
|
6f030e9672 | ||
|
|
7107d3c9e7 | ||
|
|
fbdc06ebc4 | ||
|
|
d149e755fd | ||
|
|
86ee8ccd12 | ||
|
|
8d6a1ba811 | ||
|
|
9ccb8d5f20 | ||
|
|
8e43e2574c | ||
|
|
2e70506763 | ||
|
|
7f184c8ca8 | ||
|
|
da2b307aa3 | ||
|
|
739a88ceed | ||
|
|
3ff5c7a74d | ||
|
|
1048c4a28c | ||
|
|
7de009f99a | ||
|
|
95669855fb | ||
|
|
56e7cade28 | ||
|
|
c085a53268 | ||
|
|
49569b81aa | ||
|
|
4497e8a154 | ||
|
|
b9525c5fd4 | ||
|
|
c3206f4568 | ||
|
|
9abed3fc83 | ||
|
|
63a6b7b255 | ||
|
|
15dc8e8a3f | ||
|
|
cd4a017e96 | ||
|
|
82c0207fa6 | ||
|
|
7c5e765b3b | ||
|
|
f456d97a34 | ||
|
|
8b490b1540 | ||
|
|
b3951e5885 | ||
|
|
ced9762b14 | ||
|
|
9b9bba9f02 | ||
|
|
07859a9ef3 | ||
|
|
cb74467acb | ||
|
|
62dad42152 | ||
|
|
3ec74d1e3a | ||
|
|
52aff65e35 | ||
|
|
5994fb3db5 | ||
|
|
0dbcb45d28 | ||
|
|
d71f257215 | ||
|
|
b11d234f77 | ||
|
|
0d4c5aa421 | ||
|
|
9e60f93b84 | ||
|
|
9d63e8f093 | ||
|
|
4c40253df7 | ||
|
|
491b56d051 | ||
|
|
4d530920e0 | ||
|
|
08fb9a9209 | ||
|
|
04ff2672b5 | ||
|
|
d47849a26e | ||
|
|
63ee97d0fd | ||
|
|
bd74a32b79 | ||
|
|
b990be88ef | ||
|
|
cccf5e73c0 | ||
|
|
f3f85e5a11 | ||
|
|
d55511f1dd | ||
|
|
d98c7b9ae3 | ||
|
|
a30221c5bb | ||
|
|
411e843fc4 | ||
|
|
8575d5b35c | ||
|
|
ba16e41160 | ||
|
|
708d5229ae | ||
|
|
fb4a7d65d7 | ||
|
|
d7353e6e99 | ||
|
|
48113cfaba | ||
|
|
c0b5754ef7 | ||
|
|
f2fb498c69 | ||
|
|
91e8e0e511 | ||
|
|
dfff8d23cf | ||
|
|
103d9a68fa | ||
|
|
a814fe8c5f | ||
|
|
193401e754 | ||
|
|
e1aeabde44 | ||
|
|
6d1e61173b | ||
|
|
6f82b5be4a | ||
|
|
192f1b0e2b | ||
|
|
238a796e38 | ||
|
|
fe393ac355 | ||
|
|
3ea078baf6 | ||
|
|
eb3e1ae24f | ||
|
|
c2b20c585e | ||
|
|
07561964fc | ||
|
|
ce8c1ce5b0 | ||
|
|
ef60dcac31 | ||
|
|
73bd5a19aa | ||
|
|
fef974ca5c | ||
|
|
8dbf46913b | ||
|
|
e46b188fe8 | ||
|
|
e6b1f9a4c3 | ||
|
|
39cfc8c1c0 | ||
|
|
79e25e192c | ||
|
|
792089f523 | ||
|
|
34636caa2d | ||
|
|
2993437eaa | ||
|
|
0bcc8c0211 | ||
|
|
4b54d8e15e | ||
|
|
afe52595a9 | ||
|
|
4f417262e3 | ||
|
|
1db3b38104 | ||
|
|
bc47f50926 | ||
|
|
e36b5a099c | ||
|
|
025881d0e9 | ||
|
|
320d0a5f1b | ||
|
|
d382210fce | ||
|
|
7b62767e16 | ||
|
|
6568841bb0 | ||
|
|
e361f6b284 | ||
|
|
53766917ef | ||
|
|
2a255076f5 | ||
|
|
fb080e7853 | ||
|
|
0818841038 | ||
|
|
939baebfe7 | ||
|
|
326ba26522 | ||
|
|
ec0b510f1c | ||
|
|
be626f7c53 | ||
|
|
3096e4930e | ||
|
|
33bdf44a04 | ||
|
|
ccbe31c21f | ||
|
|
c6746499c1 | ||
|
|
e1229e375f | ||
|
|
be27499d39 | ||
|
|
56a2b564ef | ||
|
|
9a00877af9 | ||
|
|
92f2a1ca69 | ||
|
|
882903f2fa | ||
|
|
54d86dd73b | ||
|
|
b496714caa | ||
|
|
3f5175584b | ||
|
|
11fff226f3 | ||
|
|
93490a0fc1 | ||
|
|
0585c3e5fd | ||
|
|
0b74f2a007 | ||
|
|
59d98b9ef6 | ||
|
|
3522451600 | ||
|
|
fe03bacd6c | ||
|
|
1f46d5945b | ||
|
|
585d73bf7c | ||
|
|
9e84cebfdb | ||
|
|
d1a2bd67da | ||
|
|
7708429d35 | ||
|
|
6045911d95 | ||
|
|
1b212aa073 | ||
|
|
4d48166835 | ||
|
|
437bac370a | ||
|
|
546062d3a3 | ||
|
|
576b93c99f | ||
|
|
180275c4e0 | ||
|
|
379e4b68f5 | ||
|
|
74b4d81992 | ||
|
|
fea8f0d5fd | ||
|
|
0e5dab5eaf | ||
|
|
c550bc154f | ||
|
|
40fcb91206 | ||
|
|
c8554ff48c | ||
|
|
3d95cef08c | ||
|
|
9cd724cf5e | ||
|
|
eb7eb5ce68 | ||
|
|
418eeb642c | ||
|
|
8ac56d004d | ||
|
|
52a76583c5 | ||
|
|
b1d02cc94f | ||
|
|
b9b488b6d3 | ||
|
|
9a2d0238a8 | ||
|
|
5cc21690eb | ||
|
|
f80f65d58c | ||
|
|
df284fbe65 | ||
|
|
b632ebf129 | ||
|
|
4b9cd8e81d | ||
|
|
6c82f4ae9b | ||
|
|
87644fa46b | ||
|
|
22dc376392 | ||
|
|
4ef1fb5a24 | ||
|
|
be6fd80a1c | ||
|
|
c48a467b8e | ||
|
|
557edbb84a | ||
|
|
0cfc6e6d95 | ||
|
|
2978106991 | ||
|
|
8517f49745 | ||
|
|
6c76b4e2f8 | ||
|
|
c91bd60051 | ||
|
|
a8739bad76 | ||
|
|
2b97442f2e | ||
|
|
5997355e22 | ||
|
|
d8bd9845cc | ||
|
|
3d1bc143af | ||
|
|
72a25f825c | ||
|
|
c4e0354876 | ||
|
|
389e820878 | ||
|
|
a2f0186427 | ||
|
|
58d670a258 | ||
|
|
ca88669435 | ||
|
|
15a9b0f2be | ||
|
|
197bf15402 | ||
|
|
0bae242cbf | ||
|
|
3352b1090e | ||
|
|
c4d17dd231 | ||
|
|
5f78f67e39 | ||
|
|
b1d99bb6b6 | ||
|
|
8914e9fd03 | ||
|
|
8d1d728d88 | ||
|
|
59c14c747a | ||
|
|
ccdf29a5f8 | ||
|
|
a7e079ea16 | ||
|
|
a97bed9d22 | ||
|
|
0ce68e97a7 | ||
|
|
3f66230874 | ||
|
|
35d0a8a843 | ||
|
|
44c3d4d2dc | ||
|
|
167772fbca | ||
|
|
2f0b11673a | ||
|
|
c5aa6a2286 | ||
|
|
d5522c3480 | ||
|
|
c1e5e6781e | ||
|
|
dd086e5bfd | ||
|
|
213bb7c6ed | ||
|
|
0c88f98a3b | ||
|
|
23ae0a9838 | ||
|
|
0f78bea4a3 | ||
|
|
4b627bd29e | ||
|
|
e4510c76e5 | ||
|
|
122dd6c11e | ||
|
|
63a5280f8f | ||
|
|
07149f576a | ||
|
|
dbd2a43ab1 | ||
|
|
4a211a9117 | ||
|
|
18ebe165ba | ||
|
|
908e1cb11a | ||
|
|
5c6c57ed89 | ||
|
|
47094fd83f | ||
|
|
67153f897e | ||
|
|
f2528dc3ac | ||
|
|
935bc162e1 | ||
|
|
d5954aff08 | ||
|
|
e98b89651e | ||
|
|
516f90abdb | ||
|
|
c09320c651 | ||
|
|
6d0812b567 | ||
|
|
b05154218c | ||
|
|
c8ae3de610 | ||
|
|
ae96aa0a6d | ||
|
|
1e85749e6e | ||
|
|
b624ed5050 | ||
|
|
b865aca03a | ||
|
|
2e7714e80c | ||
|
|
39df4f0923 | ||
|
|
eff3e01ec3 | ||
|
|
13d4504dfc | ||
|
|
9342bf685e | ||
|
|
f804c087e4 | ||
|
|
0102360e92 | ||
|
|
ca481322d4 | ||
|
|
654a7eab62 | ||
|
|
4e5b0b7eec | ||
|
|
9aaafddf04 | ||
|
|
9cd282e001 | ||
|
|
bd5dc855af | ||
|
|
31218166fc | ||
|
|
6bdecdbc5a | ||
|
|
45e6e71652 | ||
|
|
3abb32c3ba | ||
|
|
6e65343895 | ||
|
|
d1977c679b | ||
|
|
0ee44ef384 | ||
|
|
1c8f0e0fc5 | ||
|
|
17a557dfd5 | ||
|
|
8c751d48a2 | ||
|
|
5b8a7340bb | ||
|
|
33784e612a | ||
|
|
fdd5f8ff83 | ||
|
|
63616a5fce | ||
|
|
dfc00271d1 | ||
|
|
1143050ea6 | ||
|
|
5ab4a9330a | ||
|
|
2cd7c719ef | ||
|
|
ed00129866 | ||
|
|
10843805ac | ||
|
|
f0e15272b2 | ||
|
|
d4c4537b33 | ||
|
|
ba1183bb6e | ||
|
|
85ee5284f5 | ||
|
|
3795e37410 | ||
|
|
d396d8dae3 | ||
|
|
cac1d13fda | ||
|
|
80153decd1 | ||
|
|
15a2add0f8 | ||
|
|
4bcc0a0a7a | ||
|
|
542f717bf9 | ||
|
|
b5cc8b6c59 | ||
|
|
1d23e0c920 | ||
|
|
ad51795314 | ||
|
|
7d76e84953 | ||
|
|
c96e4ca121 |
@@ -32,12 +32,12 @@ jobs:
|
||||
- name: OS X
|
||||
os: macos-latest
|
||||
install_expat: "yes"
|
||||
config: "--enable-debug --disable-flto --with-ssl=/usr/local/opt/openssl --with-libexpat=/usr/local/opt/expat"
|
||||
config: "--enable-debug --disable-flto --with-ssl=/opt/homebrew/opt/openssl --with-libexpat=/opt/homebrew/opt/expat"
|
||||
make_test: "yes"
|
||||
- name: Clang on OS X
|
||||
os: macos-latest
|
||||
install_expat: "yes"
|
||||
config: "CC=clang --enable-debug --disable-flto --with-ssl=/usr/local/opt/openssl --with-libexpat=/usr/local/opt/expat --disable-static"
|
||||
config: "CC=clang --enable-debug --disable-flto --with-ssl=/opt/homebrew/opt/openssl --with-libexpat=/opt/homebrew/opt/expat --disable-static"
|
||||
make_test: "yes"
|
||||
clang_analysis: "yes"
|
||||
- name: ubsan (gcc undefined behaviour sanitizer)
|
||||
@@ -163,7 +163,7 @@ jobs:
|
||||
make: "no"
|
||||
|
||||
steps:
|
||||
- uses: actions/checkout@v3
|
||||
- uses: actions/checkout@v4
|
||||
with:
|
||||
submodules: false
|
||||
- name: test_windows
|
||||
@@ -181,21 +181,20 @@ jobs:
|
||||
export LEX="win_flex"
|
||||
echo 'YACC="win_bison -y"'
|
||||
export YACC="win_bison -y"
|
||||
#echo "curl cpanm"
|
||||
#curl -L -k -s -S -o cpanm https://cpanmin.us/
|
||||
#echo "perl cpanm Pod::Usage"
|
||||
#perl cpanm Pod::Usage
|
||||
mkdir openssl
|
||||
echo "curl openssl"
|
||||
curl -L -k -s -S -o openssl-1.1.1j.tar.gz https://www.openssl.org/source/openssl-1.1.1j.tar.gz
|
||||
tar xzf openssl-1.1.1j.tar.gz
|
||||
cd openssl-1.1.1j
|
||||
curl -L -k -s -S -o openssl-3.2.0.tar.gz https://www.openssl.org/source/openssl-3.2.0.tar.gz
|
||||
tar xzf openssl-3.2.0.tar.gz
|
||||
cd openssl-3.2.0
|
||||
# remove pod::Usage because we do not need -help or -man output
|
||||
# from the Configure script
|
||||
echo "Fixup ./Configure by removing use Pod::Usage require"
|
||||
sed -e 's/use Pod::Usage//' < Configure > Configure.fix
|
||||
echo "./Configure.fix no-shared no-asm -DOPENSSL_NO_CAPIENG mingw64 --prefix=\""$prepath/openssl\"""
|
||||
./Configure.fix no-shared no-asm -DOPENSSL_NO_CAPIENG mingw64 --prefix="$prepath/openssl"
|
||||
# from the Configure script, this fixes it for openssl 1.1.1
|
||||
#echo "Fixup ./Configure by removing use Pod::Usage require"
|
||||
#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 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
|
||||
|
||||
@@ -12,7 +12,7 @@ jobs:
|
||||
runs-on: ubuntu-latest
|
||||
|
||||
steps:
|
||||
- uses: actions/checkout@v3
|
||||
- uses: actions/checkout@v4
|
||||
- name: configure
|
||||
run: ./configure --enable-debug
|
||||
- name: make
|
||||
|
||||
@@ -10,6 +10,9 @@
|
||||
/config.status
|
||||
/dnstap/dnstap_config.h
|
||||
/dnscrypt/dnscrypt_config.h
|
||||
/util/configlexer.c
|
||||
/util/configparser.c
|
||||
/util/configparser.h
|
||||
/clubsyms.def
|
||||
/doc/example.conf
|
||||
/doc/libunbound.3
|
||||
@@ -55,6 +58,7 @@
|
||||
/pythonmod/unboundmodule.py
|
||||
/testdata/result.*
|
||||
/testdata/.done-*
|
||||
/testdata/.skip-*
|
||||
/testdata/.perfstats.txt
|
||||
/doc/html
|
||||
/doc/xml
|
||||
|
||||
+13
-10
@@ -439,7 +439,8 @@ unbound-control-setup: smallapp/unbound-control-setup.sh
|
||||
dnstap.lo dnstap.o: $(srcdir)/dnstap/dnstap.c config.h dnstap/dnstap_config.h \
|
||||
dnstap/dnstap.pb-c.c dnstap/dnstap.pb-c.h $(srcdir)/dnstap/dnstap.h \
|
||||
$(srcdir)/util/config_file.h $(srcdir)/util/log.h \
|
||||
$(srcdir)/util/netevent.h $(srcdir)/util/net_help.h
|
||||
$(srcdir)/util/netevent.h $(srcdir)/util/net_help.h \
|
||||
$(srcdir)/util/locks.h
|
||||
|
||||
dnstap/dnstap.pb-c.c dnstap/dnstap.pb-c.h: $(srcdir)/dnstap/dnstap.proto
|
||||
@-if test ! -d dnstap; then $(INSTALL) -d dnstap; fi
|
||||
@@ -738,7 +739,7 @@ msgencode.lo msgencode.o: $(srcdir)/util/data/msgencode.c config.h $(srcdir)/uti
|
||||
msgparse.lo msgparse.o: $(srcdir)/util/data/msgparse.c config.h $(srcdir)/util/data/msgparse.h \
|
||||
$(srcdir)/util/storage/lruhash.h $(srcdir)/util/locks.h $(srcdir)/util/log.h $(srcdir)/sldns/pkthdr.h \
|
||||
$(srcdir)/sldns/rrdef.h $(srcdir)/util/data/msgreply.h $(srcdir)/util/data/packed_rrset.h \
|
||||
$(srcdir)/util/data/dname.h $(srcdir)/util/storage/lookup3.h $(srcdir)/util/regional.h $(srcdir)/sldns/sbuffer.h \
|
||||
$(srcdir)/util/data/dname.h $(srcdir)/util/storage/lookup3.h $(srcdir)/util/regional.h $(srcdir)/util/net_help.h $(srcdir)/sldns/sbuffer.h \
|
||||
$(srcdir)/sldns/parseutil.h $(srcdir)/sldns/wire2str.h
|
||||
msgreply.lo msgreply.o: $(srcdir)/util/data/msgreply.c config.h $(srcdir)/util/data/msgreply.h \
|
||||
$(srcdir)/util/storage/lruhash.h $(srcdir)/util/locks.h $(srcdir)/util/log.h $(srcdir)/util/data/packed_rrset.h \
|
||||
@@ -793,7 +794,7 @@ iter_priv.lo iter_priv.o: $(srcdir)/iterator/iter_priv.c config.h $(srcdir)/iter
|
||||
$(srcdir)/util/data/msgparse.h $(srcdir)/sldns/pkthdr.h $(srcdir)/sldns/rrdef.h $(srcdir)/util/net_help.h \
|
||||
$(srcdir)/util/storage/dnstree.h $(srcdir)/sldns/str2wire.h $(srcdir)/sldns/sbuffer.h
|
||||
iter_resptype.lo iter_resptype.o: $(srcdir)/iterator/iter_resptype.c config.h \
|
||||
$(srcdir)/iterator/iter_resptype.h $(srcdir)/iterator/iter_delegpt.h $(srcdir)/util/log.h \
|
||||
$(srcdir)/iterator/iter_resptype.h $(srcdir)/iterator/iter_delegpt.h $(srcdir)/iterator/iterator.h $(srcdir)/util/log.h \
|
||||
$(srcdir)/services/cache/dns.h $(srcdir)/util/storage/lruhash.h $(srcdir)/util/locks.h \
|
||||
$(srcdir)/util/data/msgreply.h $(srcdir)/util/data/packed_rrset.h $(srcdir)/util/net_help.h \
|
||||
$(srcdir)/util/data/dname.h $(srcdir)/sldns/rrdef.h $(srcdir)/sldns/pkthdr.h
|
||||
@@ -1278,7 +1279,8 @@ daemon.lo daemon.o: $(srcdir)/daemon/daemon.c config.h $(srcdir)/daemon/daemon.h
|
||||
$(srcdir)/util/edns.h $(srcdir)/services/listen_dnsport.h $(srcdir)/services/cache/rrset.h \
|
||||
$(srcdir)/services/cache/infra.h $(srcdir)/util/rtt.h $(srcdir)/services/localzone.h \
|
||||
$(srcdir)/services/authzone.h $(srcdir)/services/mesh.h $(srcdir)/services/rpz.h $(srcdir)/respip/respip.h \
|
||||
$(srcdir)/util/random.h $(srcdir)/util/tube.h $(srcdir)/util/net_help.h $(srcdir)/sldns/keyraw.h
|
||||
$(srcdir)/util/random.h $(srcdir)/util/tube.h $(srcdir)/util/net_help.h $(srcdir)/sldns/keyraw.h \
|
||||
$(srcdir)/iterator/iter_fwd.h $(srcdir)/iterator/iter_hints.h
|
||||
remote.lo remote.o: $(srcdir)/daemon/remote.c config.h $(srcdir)/daemon/remote.h $(srcdir)/daemon/worker.h \
|
||||
$(srcdir)/libunbound/worker.h $(srcdir)/sldns/sbuffer.h $(srcdir)/util/data/packed_rrset.h \
|
||||
$(srcdir)/util/storage/lruhash.h $(srcdir)/util/locks.h $(srcdir)/util/log.h $(srcdir)/util/netevent.h \
|
||||
@@ -1355,7 +1357,7 @@ testbound.lo testbound.o: $(srcdir)/testcode/testbound.c config.h $(srcdir)/test
|
||||
$(srcdir)/util/data/msgparse.h $(srcdir)/sldns/pkthdr.h $(srcdir)/sldns/rrdef.h $(srcdir)/util/tube.h \
|
||||
$(srcdir)/services/mesh.h $(srcdir)/services/rpz.h $(srcdir)/services/localzone.h $(srcdir)/services/view.h \
|
||||
$(srcdir)/services/authzone.h $(srcdir)/daemon/stats.h $(srcdir)/util/timehist.h $(srcdir)/libunbound/unbound.h \
|
||||
$(srcdir)/respip/respip.h $(srcdir)/util/net_help.h $(srcdir)/util/ub_event.h
|
||||
$(srcdir)/respip/respip.h $(srcdir)/util/net_help.h $(srcdir)/util/ub_event.h $(srcdir)/daemon/worker.h
|
||||
testpkts.lo testpkts.o: $(srcdir)/testcode/testpkts.c config.h $(srcdir)/testcode/testpkts.h \
|
||||
$(srcdir)/util/net_help.h $(srcdir)/util/log.h $(srcdir)/sldns/sbuffer.h $(srcdir)/sldns/rrdef.h $(srcdir)/sldns/pkthdr.h \
|
||||
$(srcdir)/sldns/str2wire.h $(srcdir)/sldns/wire2str.h
|
||||
@@ -1428,7 +1430,7 @@ fake_event.lo fake_event.o: $(srcdir)/testcode/fake_event.c config.h $(srcdir)/t
|
||||
$(srcdir)/util/tube.h $(srcdir)/services/mesh.h $(srcdir)/services/modstack.h $(srcdir)/services/rpz.h \
|
||||
$(srcdir)/services/localzone.h $(srcdir)/services/view.h $(srcdir)/sldns/sbuffer.h $(srcdir)/services/authzone.h \
|
||||
$(srcdir)/daemon/stats.h $(srcdir)/util/timehist.h $(srcdir)/libunbound/unbound.h $(srcdir)/respip/respip.h \
|
||||
$(srcdir)/sldns/wire2str.h $(srcdir)/sldns/str2wire.h $(srcdir)/daemon/remote.h
|
||||
$(srcdir)/sldns/wire2str.h $(srcdir)/sldns/str2wire.h $(srcdir)/daemon/remote.h $(srcdir)/util/storage/slabhash.h $(srcdir)/daemon/daemon.h
|
||||
lock_verify.lo lock_verify.o: $(srcdir)/testcode/lock_verify.c config.h $(srcdir)/util/log.h $(srcdir)/util/rbtree.h \
|
||||
$(srcdir)/util/locks.h $(srcdir)/util/fptr_wlist.h $(srcdir)/util/netevent.h $(srcdir)/dnscrypt/dnscrypt.h \
|
||||
$(srcdir)/util/storage/lruhash.h $(srcdir)/util/module.h \
|
||||
@@ -1484,7 +1486,8 @@ context.lo context.o: $(srcdir)/libunbound/context.c config.h $(srcdir)/libunbou
|
||||
$(srcdir)/util/storage/slabhash.h $(srcdir)/services/cache/infra.h $(srcdir)/util/rtt.h \
|
||||
$(srcdir)/util/netevent.h $(srcdir)/dnscrypt/dnscrypt.h \
|
||||
$(srcdir)/services/authzone.h $(srcdir)/services/mesh.h $(srcdir)/services/rpz.h $(srcdir)/daemon/stats.h \
|
||||
$(srcdir)/util/timehist.h $(srcdir)/respip/respip.h $(srcdir)/util/edns.h
|
||||
$(srcdir)/util/timehist.h $(srcdir)/respip/respip.h $(srcdir)/util/edns.h \
|
||||
$(srcdir)/iterator/iter_fwd.h $(srcdir)/iterator/iter_hints.h
|
||||
libunbound.lo libunbound.o: $(srcdir)/libunbound/libunbound.c $(srcdir)/libunbound/unbound.h \
|
||||
$(srcdir)/libunbound/unbound-event.h config.h $(srcdir)/libunbound/context.h $(srcdir)/util/locks.h \
|
||||
$(srcdir)/util/log.h $(srcdir)/util/alloc.h $(srcdir)/util/rbtree.h $(srcdir)/services/modstack.h \
|
||||
@@ -1496,7 +1499,8 @@ libunbound.lo libunbound.o: $(srcdir)/libunbound/libunbound.c $(srcdir)/libunbou
|
||||
$(srcdir)/sldns/sbuffer.h $(srcdir)/services/cache/infra.h $(srcdir)/util/rtt.h $(srcdir)/util/netevent.h \
|
||||
$(srcdir)/dnscrypt/dnscrypt.h $(srcdir)/services/cache/rrset.h \
|
||||
$(srcdir)/util/storage/slabhash.h $(srcdir)/services/authzone.h $(srcdir)/services/mesh.h \
|
||||
$(srcdir)/services/rpz.h $(srcdir)/daemon/stats.h $(srcdir)/util/timehist.h $(srcdir)/respip/respip.h
|
||||
$(srcdir)/services/rpz.h $(srcdir)/daemon/stats.h $(srcdir)/util/timehist.h $(srcdir)/respip/respip.h \
|
||||
$(srcdir)/iterator/iter_fwd.h $(srcdir)/iterator/iter_hints.h
|
||||
libworker.lo libworker.o: $(srcdir)/libunbound/libworker.c config.h $(srcdir)/libunbound/libworker.h \
|
||||
$(srcdir)/util/data/packed_rrset.h $(srcdir)/util/storage/lruhash.h $(srcdir)/util/locks.h $(srcdir)/util/log.h \
|
||||
$(srcdir)/libunbound/context.h $(srcdir)/util/alloc.h $(srcdir)/util/rbtree.h $(srcdir)/services/modstack.h \
|
||||
@@ -1510,8 +1514,7 @@ libworker.lo libworker.o: $(srcdir)/libunbound/libworker.c config.h $(srcdir)/li
|
||||
$(srcdir)/services/cache/rrset.h $(srcdir)/util/storage/slabhash.h $(srcdir)/services/outbound_list.h \
|
||||
$(srcdir)/util/fptr_wlist.h $(srcdir)/util/tube.h $(srcdir)/util/regional.h $(srcdir)/util/random.h \
|
||||
$(srcdir)/util/storage/lookup3.h $(srcdir)/util/net_help.h $(srcdir)/util/data/dname.h \
|
||||
$(srcdir)/util/data/msgencode.h $(srcdir)/iterator/iter_fwd.h $(srcdir)/iterator/iter_hints.h \
|
||||
$(srcdir)/sldns/str2wire.h
|
||||
$(srcdir)/util/data/msgencode.h $(srcdir)/sldns/str2wire.h
|
||||
unbound-host.lo unbound-host.o: $(srcdir)/smallapp/unbound-host.c config.h $(srcdir)/libunbound/unbound.h \
|
||||
$(srcdir)/sldns/rrdef.h $(srcdir)/sldns/wire2str.h
|
||||
asynclook.lo asynclook.o: $(srcdir)/testcode/asynclook.c config.h $(srcdir)/libunbound/unbound.h \
|
||||
|
||||
@@ -17,7 +17,9 @@ You can learn more about Unbound by reading our
|
||||
## Compiling
|
||||
|
||||
Make sure you have the C toolchain, OpenSSL and its include files, and libexpat
|
||||
installed. Unbound can be compiled and installed using:
|
||||
installed.
|
||||
If building from the repository source you also need flex and bison installed.
|
||||
Unbound can be compiled and installed using:
|
||||
|
||||
```
|
||||
./configure && make && make install
|
||||
@@ -27,7 +29,7 @@ You can use libevent if you want. libevent is useful when using many (10000)
|
||||
outgoing ports. By default max 256 ports are opened at the same time and the
|
||||
builtin alternative is equally capable and a little faster.
|
||||
|
||||
Use the `--with-libevent=dir` configure option to compile Unbound with libevent
|
||||
Use the `--with-libevent` configure option to compile Unbound with libevent
|
||||
support.
|
||||
|
||||
## Unbound configuration
|
||||
|
||||
+88
-33
@@ -2,7 +2,10 @@
|
||||
# Copyright 2009, Wouter Wijngaards, NLnet Labs.
|
||||
# BSD licensed.
|
||||
#
|
||||
# Version 46
|
||||
# Version 48
|
||||
# 2024-01-16 fix to add -l:libssp.a to -lcrypto link check.
|
||||
# and check for getaddrinfo with only header.
|
||||
# 2024-01-15 fix to add crypt32 to -lcrypto link check when checking for gdi32.
|
||||
# 2023-05-04 fix to remove unused whitespace.
|
||||
# 2023-01-26 fix -Wstrict-prototypes.
|
||||
# 2022-09-01 fix checking if nonblocking sockets work on OpenBSD.
|
||||
@@ -707,7 +710,7 @@ AC_DEFUN([ACX_SSL_CHECKS], [
|
||||
LIBSSL_LDFLAGS="$LIBSSL_LDFLAGS -L$ssldir_lib"
|
||||
ACX_RUNTIME_PATH_ADD([$ssldir_lib])
|
||||
fi
|
||||
|
||||
|
||||
AC_MSG_CHECKING([for EVP_sha256 in -lcrypto])
|
||||
LIBS="$LIBS -lcrypto"
|
||||
LIBSSL_LIBS="$LIBSSL_LIBS -lcrypto"
|
||||
@@ -732,40 +735,73 @@ AC_DEFUN([ACX_SSL_CHECKS], [
|
||||
]])],[
|
||||
AC_DEFINE([HAVE_EVP_SHA256], 1,
|
||||
[If you have EVP_sha256])
|
||||
AC_MSG_RESULT(yes)
|
||||
AC_MSG_RESULT(yes)
|
||||
],[
|
||||
AC_MSG_RESULT(no)
|
||||
LIBS="$BAKLIBS"
|
||||
LIBSSL_LIBS="$BAKSSLLIBS"
|
||||
LIBS="$LIBS -ldl"
|
||||
LIBSSL_LIBS="$LIBSSL_LIBS -ldl"
|
||||
AC_MSG_CHECKING([if -lcrypto needs -ldl])
|
||||
AC_LINK_IFELSE([AC_LANG_PROGRAM([[]], [[
|
||||
int EVP_sha256(void);
|
||||
(void)EVP_sha256();
|
||||
]])],[
|
||||
AC_DEFINE([HAVE_EVP_SHA256], 1,
|
||||
[If you have EVP_sha256])
|
||||
AC_MSG_RESULT(yes)
|
||||
],[
|
||||
AC_MSG_RESULT(no)
|
||||
LIBS="$BAKLIBS"
|
||||
LIBSSL_LIBS="$BAKSSLLIBS"
|
||||
LIBS="$LIBS -ldl -pthread"
|
||||
LIBSSL_LIBS="$LIBSSL_LIBS -ldl -pthread"
|
||||
AC_MSG_CHECKING([if -lcrypto needs -ldl -pthread])
|
||||
AC_LINK_IFELSE([AC_LANG_PROGRAM([[]], [[
|
||||
int EVP_sha256(void);
|
||||
(void)EVP_sha256();
|
||||
]])],[
|
||||
AC_DEFINE([HAVE_EVP_SHA256], 1,
|
||||
[If you have EVP_sha256])
|
||||
AC_MSG_RESULT(yes)
|
||||
],[
|
||||
AC_MSG_RESULT(no)
|
||||
AC_MSG_ERROR([OpenSSL found in $ssldir, but version 0.9.7 or higher is required])
|
||||
|
||||
LIBS="$LIBS -lgdi32 -lws2_32 -lcrypt32"
|
||||
LIBSSL_LIBS="$LIBSSL_LIBS -lgdi32 -lws2_32 -lcrypt32"
|
||||
AC_MSG_CHECKING([if -lcrypto needs -lgdi32 -lws2_32 -lcrypt32])
|
||||
AC_LINK_IFELSE([AC_LANG_PROGRAM([[]], [[
|
||||
int EVP_sha256(void);
|
||||
(void)EVP_sha256();
|
||||
]])],[
|
||||
AC_DEFINE([HAVE_EVP_SHA256], 1,
|
||||
[If you have EVP_sha256])
|
||||
AC_MSG_RESULT(yes)
|
||||
],[
|
||||
AC_MSG_RESULT(no)
|
||||
LIBS="$BAKLIBS"
|
||||
LIBSSL_LIBS="$BAKSSLLIBS"
|
||||
|
||||
LIBS="$LIBS -lgdi32 -lws2_32 -lcrypt32 -l:libssp.a"
|
||||
LIBSSL_LIBS="$LIBSSL_LIBS -lgdi32 -lws2_32 -lcrypt32 -l:libssp.a"
|
||||
AC_MSG_CHECKING([if -lcrypto needs -lgdi32 -lws2_32 -lcrypt32 -l:libssp.a])
|
||||
AC_LINK_IFELSE([AC_LANG_PROGRAM([[]], [[
|
||||
int EVP_sha256(void);
|
||||
(void)EVP_sha256();
|
||||
]])],[
|
||||
AC_DEFINE([HAVE_EVP_SHA256], 1,
|
||||
[If you have EVP_sha256])
|
||||
AC_MSG_RESULT(yes)
|
||||
],[
|
||||
AC_MSG_RESULT(no)
|
||||
LIBS="$BAKLIBS"
|
||||
LIBSSL_LIBS="$BAKSSLLIBS"
|
||||
|
||||
LIBS="$LIBS -ldl"
|
||||
LIBSSL_LIBS="$LIBSSL_LIBS -ldl"
|
||||
AC_MSG_CHECKING([if -lcrypto needs -ldl])
|
||||
AC_LINK_IFELSE([AC_LANG_PROGRAM([[]], [[
|
||||
int EVP_sha256(void);
|
||||
(void)EVP_sha256();
|
||||
]])],[
|
||||
AC_DEFINE([HAVE_EVP_SHA256], 1,
|
||||
[If you have EVP_sha256])
|
||||
AC_MSG_RESULT(yes)
|
||||
],[
|
||||
AC_MSG_RESULT(no)
|
||||
LIBS="$BAKLIBS"
|
||||
LIBSSL_LIBS="$BAKSSLLIBS"
|
||||
LIBS="$LIBS -ldl -pthread"
|
||||
LIBSSL_LIBS="$LIBSSL_LIBS -ldl -pthread"
|
||||
AC_MSG_CHECKING([if -lcrypto needs -ldl -pthread])
|
||||
AC_LINK_IFELSE([AC_LANG_PROGRAM([[]], [[
|
||||
int EVP_sha256(void);
|
||||
(void)EVP_sha256();
|
||||
]])],[
|
||||
AC_DEFINE([HAVE_EVP_SHA256], 1,
|
||||
[If you have EVP_sha256])
|
||||
AC_MSG_RESULT(yes)
|
||||
],[
|
||||
AC_MSG_RESULT(no)
|
||||
AC_MSG_ERROR([OpenSSL found in $ssldir, but version 0.9.7 or higher is required])
|
||||
])
|
||||
])
|
||||
])
|
||||
])
|
||||
])
|
||||
])
|
||||
])
|
||||
fi
|
||||
@@ -779,7 +815,7 @@ AC_CHECK_HEADERS([openssl/rand.h],,, [AC_INCLUDES_DEFAULT])
|
||||
|
||||
dnl Check for SSL, where SSL is mandatory
|
||||
dnl Adds --with-ssl option, searches for openssl and defines HAVE_SSL if found
|
||||
dnl Setup of CPPFLAGS, CFLAGS. Adds -lcrypto to LIBS.
|
||||
dnl Setup of CPPFLAGS, CFLAGS. Adds -lcrypto to LIBS.
|
||||
dnl Checks main header files of SSL.
|
||||
dnl
|
||||
AC_DEFUN([ACX_WITH_SSL],
|
||||
@@ -872,7 +908,7 @@ dnl see if on windows
|
||||
if test "$ac_cv_header_windows_h" = "yes"; then
|
||||
AC_DEFINE(USE_WINSOCK, 1, [Whether the windows socket API is used])
|
||||
USE_WINSOCK="1"
|
||||
if echo $LIBS | grep 'lws2_32' >/dev/null; then
|
||||
if echo "$LIBS" | grep 'lws2_32' >/dev/null; then
|
||||
:
|
||||
else
|
||||
LIBS="$LIBS -lws2_32"
|
||||
@@ -880,6 +916,24 @@ if test "$ac_cv_header_windows_h" = "yes"; then
|
||||
fi
|
||||
],
|
||||
dnl no quick getaddrinfo, try mingw32 and winsock2 library.
|
||||
dnl perhaps getaddrinfo needs only the include
|
||||
AC_LINK_IFELSE(
|
||||
[AC_LANG_PROGRAM(
|
||||
[
|
||||
#ifdef HAVE_WS2TCPIP_H
|
||||
#include <ws2tcpip.h>
|
||||
#endif
|
||||
],
|
||||
[
|
||||
(void)getaddrinfo(NULL, NULL, NULL, NULL);
|
||||
]
|
||||
)],
|
||||
[
|
||||
ac_cv_func_getaddrinfo="yes"
|
||||
AC_DEFINE(USE_WINSOCK, 1, [Whether the windows socket API is used])
|
||||
USE_WINSOCK="1"
|
||||
],
|
||||
|
||||
ORIGLIBS="$LIBS"
|
||||
LIBS="$LIBS -lws2_32"
|
||||
AC_LINK_IFELSE(
|
||||
@@ -904,6 +958,7 @@ ac_cv_func_getaddrinfo="no"
|
||||
LIBS="$ORIGLIBS"
|
||||
])
|
||||
)
|
||||
)
|
||||
|
||||
AC_MSG_RESULT($ac_cv_func_getaddrinfo)
|
||||
if test $ac_cv_func_getaddrinfo = yes; then
|
||||
|
||||
+1
-1
@@ -9,7 +9,7 @@ AC_DEFUN([AC_PYTHON_DEVEL],[
|
||||
|
||||
AC_PATH_PROG([PYTHON],[python[$PYTHON_VERSION]])
|
||||
if test -z "$PYTHON"; then
|
||||
AC_MSG_ERROR([Cannot find python$PYTHON_VERSION in your system path])
|
||||
AC_MSG_ERROR([Cannot find 'python$PYTHON_VERSION' in your system path. You can use the environment variable 'PYTHON_VERSION=version_number' for an explicit version.])
|
||||
PYTHON_VERSION=""
|
||||
fi
|
||||
|
||||
|
||||
@@ -1,39 +1,43 @@
|
||||
# ===========================================================================
|
||||
# http://autoconf-archive.cryp.to/ac_pkg_swig.html
|
||||
# https://www.gnu.org/software/autoconf-archive/ax_pkg_swig.html
|
||||
# ===========================================================================
|
||||
#
|
||||
# SYNOPSIS
|
||||
#
|
||||
# AC_PROG_SWIG([major.minor.micro])
|
||||
# AX_PKG_SWIG([major.minor.micro], [action-if-found], [action-if-not-found])
|
||||
#
|
||||
# DESCRIPTION
|
||||
#
|
||||
# This macro searches for a SWIG installation on your system. If found you
|
||||
# should call SWIG via $(SWIG). You can use the optional first argument to
|
||||
# check if the version of the available SWIG is greater than or equal to
|
||||
# the value of the argument. It should have the format: N[.N[.N]] (N is a
|
||||
# number between 0 and 999. Only the first N is mandatory.)
|
||||
# This macro searches for a SWIG installation on your system. If found,
|
||||
# then SWIG is AC_SUBST'd; if not found, then $SWIG is empty. If SWIG is
|
||||
# found, then SWIG_LIB is set to the SWIG library path, and AC_SUBST'd.
|
||||
#
|
||||
# If the version argument is given (e.g. 1.3.17), AC_PROG_SWIG checks that
|
||||
# the swig package is this version number or higher.
|
||||
# You can use the optional first argument to check if the version of the
|
||||
# available SWIG is greater than or equal to the value of the argument. It
|
||||
# should have the format: N[.N[.N]] (N is a number between 0 and 999. Only
|
||||
# the first N is mandatory.) If the version argument is given (e.g.
|
||||
# 1.3.17), AX_PKG_SWIG checks that the swig package is this version number
|
||||
# or higher.
|
||||
#
|
||||
# As usual, action-if-found is executed if SWIG is found, otherwise
|
||||
# action-if-not-found is executed.
|
||||
#
|
||||
# In configure.in, use as:
|
||||
#
|
||||
# AC_PROG_SWIG(1.3.17)
|
||||
# SWIG_ENABLE_CXX
|
||||
# SWIG_MULTI_MODULE_SUPPORT
|
||||
# SWIG_PYTHON
|
||||
# AX_PKG_SWIG(1.3.17, [], [ AC_MSG_ERROR([SWIG is required to build..]) ])
|
||||
# AX_SWIG_ENABLE_CXX
|
||||
# AX_SWIG_MULTI_MODULE_SUPPORT
|
||||
# AX_SWIG_PYTHON
|
||||
#
|
||||
# LAST MODIFICATION
|
||||
#
|
||||
# 2008-04-12
|
||||
#
|
||||
# COPYLEFT
|
||||
# LICENSE
|
||||
#
|
||||
# Copyright (c) 2008 Sebastian Huber <sebastian-huber@web.de>
|
||||
# Copyright (c) 2008 Alan W. Irwin <irwin@beluga.phys.uvic.ca>
|
||||
# Copyright (c) 2008 Alan W. Irwin
|
||||
# Copyright (c) 2008 Rafael Laboissiere <rafael@laboissiere.net>
|
||||
# Copyright (c) 2008 Andrew Collier <colliera@ukzn.ac.za>
|
||||
# Copyright (c) 2008 Andrew Collier
|
||||
# Copyright (c) 2011 Murray Cumming <murrayc@openismus.com>
|
||||
# Copyright (c) 2018 Reini Urban <rurban@cpan.org>
|
||||
# Copyright (c) 2021 Vincent Danjean <Vincent.Danjean@ens-lyon.org>
|
||||
#
|
||||
# This program is free software; you can redistribute it and/or modify it
|
||||
# under the terms of the GNU General Public License as published by the
|
||||
@@ -46,7 +50,7 @@
|
||||
# Public License for more details.
|
||||
#
|
||||
# You should have received a copy of the GNU General Public License along
|
||||
# with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
# with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
#
|
||||
# As a special exception, the respective Autoconf Macro's copyright owner
|
||||
# gives unlimited permission to copy, distribute and modify the configure
|
||||
@@ -57,17 +61,21 @@
|
||||
# all other use of the material that constitutes the Autoconf Macro.
|
||||
#
|
||||
# This special exception to the GPL applies to versions of the Autoconf
|
||||
# Macro released by the Autoconf Macro Archive. When you make and
|
||||
# distribute a modified version of the Autoconf Macro, you may extend this
|
||||
# special exception to the GPL to apply to your modified version as well.
|
||||
# Macro released by the Autoconf Archive. When you make and distribute a
|
||||
# modified version of the Autoconf Macro, you may extend this special
|
||||
# exception to the GPL to apply to your modified version as well.
|
||||
|
||||
AC_DEFUN([AC_PROG_SWIG],[
|
||||
AC_PATH_PROG([SWIG],[swig])
|
||||
#serial 15
|
||||
|
||||
AC_DEFUN([AX_PKG_SWIG],[
|
||||
# Find path to the "swig" executable.
|
||||
AC_PATH_PROGS([SWIG],[swig swig3.0 swig2.0])
|
||||
if test -z "$SWIG" ; then
|
||||
AC_MSG_WARN([cannot find 'swig' program. You should look at http://www.swig.org])
|
||||
SWIG='echo "Error: SWIG is not installed. You should look at http://www.swig.org" ; false'
|
||||
elif test -n "$1" ; then
|
||||
AC_MSG_CHECKING([for SWIG version])
|
||||
m4_ifval([$3],[$3],[:])
|
||||
elif test -z "$1" ; then
|
||||
m4_ifval([$2],[$2],[:])
|
||||
else
|
||||
AC_MSG_CHECKING([SWIG version])
|
||||
[swig_version=`$SWIG -version 2>&1 | grep 'SWIG Version' | sed 's/.*\([0-9][0-9]*\.[0-9][0-9]*\.[0-9][0-9]*\).*/\1/g'`]
|
||||
AC_MSG_RESULT([$swig_version])
|
||||
if test -n "$swig_version" ; then
|
||||
@@ -77,12 +85,12 @@ AC_DEFUN([AC_PROG_SWIG],[
|
||||
if test -z "$required_major" ; then
|
||||
[required_major=0]
|
||||
fi
|
||||
[required=`echo $required | sed 's/[0-9]*[^0-9]//'`]
|
||||
[required=`echo $required. | sed 's/[0-9]*[^0-9]//'`]
|
||||
[required_minor=`echo $required | sed 's/[^0-9].*//'`]
|
||||
if test -z "$required_minor" ; then
|
||||
[required_minor=0]
|
||||
fi
|
||||
[required=`echo $required | sed 's/[0-9]*[^0-9]//'`]
|
||||
[required=`echo $required. | sed 's/[0-9]*[^0-9]//'`]
|
||||
[required_patch=`echo $required | sed 's/[^0-9].*//'`]
|
||||
if test -z "$required_patch" ; then
|
||||
[required_patch=0]
|
||||
@@ -103,30 +111,28 @@ AC_DEFUN([AC_PROG_SWIG],[
|
||||
if test -z "$available_patch" ; then
|
||||
[available_patch=0]
|
||||
fi
|
||||
[badversion=0]
|
||||
if test $available_major -lt $required_major ; then
|
||||
[badversion=1]
|
||||
fi
|
||||
if test $available_major -eq $required_major \
|
||||
-a $available_minor -lt $required_minor ; then
|
||||
[badversion=1]
|
||||
fi
|
||||
if test $available_major -eq $required_major \
|
||||
-a $available_minor -eq $required_minor \
|
||||
-a $available_patch -lt $required_patch ; then
|
||||
[badversion=1]
|
||||
fi
|
||||
if test $badversion -eq 1 ; then
|
||||
AC_MSG_WARN([SWIG version >= $1 is required. You have $swig_version. You should look at http://www.swig.org])
|
||||
SWIG='echo "Error: SWIG version >= $1 is required. You have '"$swig_version"'. You should look at http://www.swig.org" ; false'
|
||||
# Convert the version tuple into a single number for easier comparison.
|
||||
# Using base 100 should be safe since SWIG internally uses BCD values
|
||||
# to encode its version number.
|
||||
required_swig_vernum=`expr $required_major \* 10000 \
|
||||
\+ $required_minor \* 100 \+ $required_patch`
|
||||
available_swig_vernum=`expr $available_major \* 10000 \
|
||||
\+ $available_minor \* 100 \+ $available_patch`
|
||||
|
||||
if test $available_swig_vernum -lt $required_swig_vernum; then
|
||||
AC_MSG_WARN([SWIG version >= $1 is required. You have $swig_version.])
|
||||
SWIG=''
|
||||
m4_ifval([$3],[$3],[])
|
||||
else
|
||||
AC_MSG_NOTICE([SWIG executable is '$SWIG'])
|
||||
SWIG_LIB=`$SWIG -swiglib`
|
||||
AC_MSG_NOTICE([SWIG library directory is '$SWIG_LIB'])
|
||||
AC_MSG_CHECKING([for SWIG library])
|
||||
SWIG_LIB=`$SWIG -swiglib | tr '\r\n' ' '`
|
||||
AC_MSG_RESULT([$SWIG_LIB])
|
||||
m4_ifval([$2],[$2],[])
|
||||
fi
|
||||
else
|
||||
AC_MSG_WARN([cannot determine SWIG version])
|
||||
SWIG='echo "Error: Cannot determine SWIG version. You should look at http://www.swig.org" ; false'
|
||||
SWIG=''
|
||||
m4_ifval([$3],[$3],[])
|
||||
fi
|
||||
fi
|
||||
AC_SUBST([SWIG_LIB])
|
||||
+317
-127
@@ -1,5 +1,5 @@
|
||||
# ===========================================================================
|
||||
# http://www.gnu.org/software/autoconf-archive/ax_pthread.html
|
||||
# https://www.gnu.org/software/autoconf-archive/ax_pthread.html
|
||||
# ===========================================================================
|
||||
#
|
||||
# SYNOPSIS
|
||||
@@ -14,24 +14,28 @@
|
||||
# flags that are needed. (The user can also force certain compiler
|
||||
# flags/libs to be tested by setting these environment variables.)
|
||||
#
|
||||
# Also sets PTHREAD_CC to any special C compiler that is needed for
|
||||
# multi-threaded programs (defaults to the value of CC otherwise). (This
|
||||
# is necessary on AIX to use the special cc_r compiler alias.)
|
||||
# Also sets PTHREAD_CC and PTHREAD_CXX to any special C compiler that is
|
||||
# needed for multi-threaded programs (defaults to the value of CC
|
||||
# respectively CXX otherwise). (This is necessary on e.g. AIX to use the
|
||||
# special cc_r/CC_r compiler alias.)
|
||||
#
|
||||
# NOTE: You are assumed to not only compile your program with these flags,
|
||||
# but also link it with them as well. e.g. you should link with
|
||||
# but also to link with them as well. For example, you might link with
|
||||
# $PTHREAD_CC $CFLAGS $PTHREAD_CFLAGS $LDFLAGS ... $PTHREAD_LIBS $LIBS
|
||||
# $PTHREAD_CXX $CXXFLAGS $PTHREAD_CFLAGS $LDFLAGS ... $PTHREAD_LIBS $LIBS
|
||||
#
|
||||
# If you are only building threads programs, you may wish to use these
|
||||
# If you are only building threaded programs, you may wish to use these
|
||||
# variables in your default LIBS, CFLAGS, and CC:
|
||||
#
|
||||
# LIBS="$PTHREAD_LIBS $LIBS"
|
||||
# CFLAGS="$CFLAGS $PTHREAD_CFLAGS"
|
||||
# CXXFLAGS="$CXXFLAGS $PTHREAD_CFLAGS"
|
||||
# CC="$PTHREAD_CC"
|
||||
# CXX="$PTHREAD_CXX"
|
||||
#
|
||||
# In addition, if the PTHREAD_CREATE_JOINABLE thread-attribute constant
|
||||
# has a nonstandard name, defines PTHREAD_CREATE_JOINABLE to that name
|
||||
# (e.g. PTHREAD_CREATE_UNDETACHED on AIX).
|
||||
# has a nonstandard name, this macro defines PTHREAD_CREATE_JOINABLE to
|
||||
# that name (e.g. PTHREAD_CREATE_UNDETACHED on AIX).
|
||||
#
|
||||
# Also HAVE_PTHREAD_PRIO_INHERIT is defined if pthread is found and the
|
||||
# PTHREAD_PRIO_INHERIT symbol is defined when compiling with
|
||||
@@ -55,6 +59,7 @@
|
||||
#
|
||||
# Copyright (c) 2008 Steven G. Johnson <stevenj@alum.mit.edu>
|
||||
# Copyright (c) 2011 Daniel Richard G. <skunk@iSKUNK.ORG>
|
||||
# Copyright (c) 2019 Marc Stevens <marc.stevens@cwi.nl>
|
||||
#
|
||||
# This program is free software: you can redistribute it and/or modify it
|
||||
# under the terms of the GNU General Public License as published by the
|
||||
@@ -67,7 +72,7 @@
|
||||
# Public License for more details.
|
||||
#
|
||||
# You should have received a copy of the GNU General Public License along
|
||||
# with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
# with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
#
|
||||
# As a special exception, the respective Autoconf Macro's copyright owner
|
||||
# gives unlimited permission to copy, distribute and modify the configure
|
||||
@@ -82,35 +87,41 @@
|
||||
# modified version of the Autoconf Macro, you may extend this special
|
||||
# exception to the GPL to apply to your modified version as well.
|
||||
|
||||
#serial 21
|
||||
#serial 31
|
||||
|
||||
AU_ALIAS([ACX_PTHREAD], [AX_PTHREAD])
|
||||
AC_DEFUN([AX_PTHREAD], [
|
||||
AC_REQUIRE([AC_CANONICAL_HOST])
|
||||
AC_REQUIRE([AC_PROG_CC])
|
||||
AC_REQUIRE([AC_PROG_SED])
|
||||
AC_LANG_PUSH([C])
|
||||
ax_pthread_ok=no
|
||||
|
||||
# We used to check for pthread.h first, but this fails if pthread.h
|
||||
# requires special compiler flags (e.g. on True64 or Sequent).
|
||||
# requires special compiler flags (e.g. on Tru64 or Sequent).
|
||||
# It gets checked for in the link test anyway.
|
||||
|
||||
# First of all, check if the user has set any of the PTHREAD_LIBS,
|
||||
# etcetera environment variables, and if threads linking works using
|
||||
# them:
|
||||
if test x"$PTHREAD_LIBS$PTHREAD_CFLAGS" != x; then
|
||||
save_CFLAGS="$CFLAGS"
|
||||
if test "x$PTHREAD_CFLAGS$PTHREAD_LIBS" != "x"; then
|
||||
ax_pthread_save_CC="$CC"
|
||||
ax_pthread_save_CFLAGS="$CFLAGS"
|
||||
ax_pthread_save_LIBS="$LIBS"
|
||||
AS_IF([test "x$PTHREAD_CC" != "x"], [CC="$PTHREAD_CC"])
|
||||
AS_IF([test "x$PTHREAD_CXX" != "x"], [CXX="$PTHREAD_CXX"])
|
||||
CFLAGS="$CFLAGS $PTHREAD_CFLAGS"
|
||||
save_LIBS="$LIBS"
|
||||
LIBS="$PTHREAD_LIBS $LIBS"
|
||||
AC_MSG_CHECKING([for pthread_join in LIBS=$PTHREAD_LIBS with CFLAGS=$PTHREAD_CFLAGS])
|
||||
AC_TRY_LINK_FUNC([pthread_join], [ax_pthread_ok=yes])
|
||||
AC_MSG_CHECKING([for pthread_join using $CC $PTHREAD_CFLAGS $PTHREAD_LIBS])
|
||||
AC_LINK_IFELSE([AC_LANG_CALL([], [pthread_join])], [ax_pthread_ok=yes])
|
||||
AC_MSG_RESULT([$ax_pthread_ok])
|
||||
if test x"$ax_pthread_ok" = xno; then
|
||||
if test "x$ax_pthread_ok" = "xno"; then
|
||||
PTHREAD_LIBS=""
|
||||
PTHREAD_CFLAGS=""
|
||||
fi
|
||||
LIBS="$save_LIBS"
|
||||
CFLAGS="$save_CFLAGS"
|
||||
CC="$ax_pthread_save_CC"
|
||||
CFLAGS="$ax_pthread_save_CFLAGS"
|
||||
LIBS="$ax_pthread_save_LIBS"
|
||||
fi
|
||||
|
||||
# We must check for the threads library under a number of different
|
||||
@@ -118,12 +129,14 @@ fi
|
||||
# (e.g. DEC) have both -lpthread and -lpthreads, where one of the
|
||||
# libraries is broken (non-POSIX).
|
||||
|
||||
# Create a list of thread flags to try. Items starting with a "-" are
|
||||
# C compiler flags, and other items are library names, except for "none"
|
||||
# which indicates that we try without any flags at all, and "pthread-config"
|
||||
# which is a program returning the flags for the Pth emulation library.
|
||||
# Create a list of thread flags to try. Items with a "," contain both
|
||||
# C compiler flags (before ",") and linker flags (after ","). Other items
|
||||
# starting with a "-" are C compiler flags, and remaining items are
|
||||
# library names, except for "none" which indicates that we try without
|
||||
# any flags at all, and "pthread-config" which is a program returning
|
||||
# the flags for the Pth emulation library.
|
||||
|
||||
ax_pthread_flags="pthreads none -Kthread -kthread lthread -pthread -pthreads -mthreads pthread --thread-safe -mt pthread-config"
|
||||
ax_pthread_flags="pthreads none -Kthread -pthread -pthreads -mthreads pthread --thread-safe -mt pthread-config"
|
||||
|
||||
# The ordering *is* (sometimes) important. Some notes on the
|
||||
# individual items follow:
|
||||
@@ -132,82 +145,163 @@ ax_pthread_flags="pthreads none -Kthread -kthread lthread -pthread -pthreads -mt
|
||||
# none: in case threads are in libc; should be tried before -Kthread and
|
||||
# other compiler flags to prevent continual compiler warnings
|
||||
# -Kthread: Sequent (threads in libc, but -Kthread needed for pthread.h)
|
||||
# -kthread: FreeBSD kernel threads (preferred to -pthread since SMP-able)
|
||||
# lthread: LinuxThreads port on FreeBSD (also preferred to -pthread)
|
||||
# -pthread: Linux/gcc (kernel threads), BSD/gcc (userland threads)
|
||||
# -pthreads: Solaris/gcc
|
||||
# -mthreads: Mingw32/gcc, Lynx/gcc
|
||||
# -pthread: Linux/gcc (kernel threads), BSD/gcc (userland threads), Tru64
|
||||
# (Note: HP C rejects this with "bad form for `-t' option")
|
||||
# -pthreads: Solaris/gcc (Note: HP C also rejects)
|
||||
# -mt: Sun Workshop C (may only link SunOS threads [-lthread], but it
|
||||
# doesn't hurt to check since this sometimes defines pthreads too;
|
||||
# also defines -D_REENTRANT)
|
||||
# ... -mt is also the pthreads flag for HP/aCC
|
||||
# doesn't hurt to check since this sometimes defines pthreads and
|
||||
# -D_REENTRANT too), HP C (must be checked before -lpthread, which
|
||||
# is present but should not be used directly; and before -mthreads,
|
||||
# because the compiler interprets this as "-mt" + "-hreads")
|
||||
# -mthreads: Mingw32/gcc, Lynx/gcc
|
||||
# pthread: Linux, etcetera
|
||||
# --thread-safe: KAI C++
|
||||
# pthread-config: use pthread-config program (for GNU Pth library)
|
||||
|
||||
case ${host_os} in
|
||||
case $host_os in
|
||||
|
||||
freebsd*)
|
||||
|
||||
# -kthread: FreeBSD kernel threads (preferred to -pthread since SMP-able)
|
||||
# lthread: LinuxThreads port on FreeBSD (also preferred to -pthread)
|
||||
|
||||
ax_pthread_flags="-kthread lthread $ax_pthread_flags"
|
||||
;;
|
||||
|
||||
hpux*)
|
||||
|
||||
# From the cc(1) man page: "[-mt] Sets various -D flags to enable
|
||||
# multi-threading and also sets -lpthread."
|
||||
|
||||
ax_pthread_flags="-mt -pthread pthread $ax_pthread_flags"
|
||||
;;
|
||||
|
||||
openedition*)
|
||||
|
||||
# IBM z/OS requires a feature-test macro to be defined in order to
|
||||
# enable POSIX threads at all, so give the user a hint if this is
|
||||
# not set. (We don't define these ourselves, as they can affect
|
||||
# other portions of the system API in unpredictable ways.)
|
||||
|
||||
AC_EGREP_CPP([AX_PTHREAD_ZOS_MISSING],
|
||||
[
|
||||
# if !defined(_OPEN_THREADS) && !defined(_UNIX03_THREADS)
|
||||
AX_PTHREAD_ZOS_MISSING
|
||||
# endif
|
||||
],
|
||||
[AC_MSG_WARN([IBM z/OS requires -D_OPEN_THREADS or -D_UNIX03_THREADS to enable pthreads support.])])
|
||||
;;
|
||||
|
||||
solaris*)
|
||||
|
||||
# On Solaris (at least, for some versions), libc contains stubbed
|
||||
# (non-functional) versions of the pthreads routines, so link-based
|
||||
# tests will erroneously succeed. (We need to link with -pthreads/-mt/
|
||||
# -lpthread.) (The stubs are missing pthread_cleanup_push, or rather
|
||||
# a function called by this macro, so we could check for that, but
|
||||
# who knows whether they'll stub that too in a future libc.) So,
|
||||
# we'll just look for -pthreads and -lpthread first:
|
||||
# tests will erroneously succeed. (N.B.: The stubs are missing
|
||||
# pthread_cleanup_push, or rather a function called by this macro,
|
||||
# so we could check for that, but who knows whether they'll stub
|
||||
# that too in a future libc.) So we'll check first for the
|
||||
# standard Solaris way of linking pthreads (-mt -lpthread).
|
||||
|
||||
ax_pthread_flags="-pthreads pthread -mt -pthread $ax_pthread_flags"
|
||||
;;
|
||||
|
||||
darwin*)
|
||||
ax_pthread_flags="-pthread $ax_pthread_flags"
|
||||
ax_pthread_flags="-mt,-lpthread pthread $ax_pthread_flags"
|
||||
;;
|
||||
esac
|
||||
|
||||
# Clang doesn't consider unrecognized options an error unless we specify
|
||||
# -Werror. We throw in some extra Clang-specific options to ensure that
|
||||
# this doesn't happen for GCC, which also accepts -Werror.
|
||||
# Are we compiling with Clang?
|
||||
|
||||
AC_MSG_CHECKING([if compiler needs -Werror to reject unknown flags])
|
||||
save_CFLAGS="$CFLAGS"
|
||||
ax_pthread_extra_flags="-Werror"
|
||||
CFLAGS="$CFLAGS $ax_pthread_extra_flags -Wunknown-warning-option -Wsizeof-array-argument"
|
||||
AC_COMPILE_IFELSE([AC_LANG_PROGRAM([int foo(void);],[foo()])],
|
||||
[AC_MSG_RESULT([yes])],
|
||||
[ax_pthread_extra_flags=
|
||||
AC_MSG_RESULT([no])])
|
||||
CFLAGS="$save_CFLAGS"
|
||||
AC_CACHE_CHECK([whether $CC is Clang],
|
||||
[ax_cv_PTHREAD_CLANG],
|
||||
[ax_cv_PTHREAD_CLANG=no
|
||||
# Note that Autoconf sets GCC=yes for Clang as well as GCC
|
||||
if test "x$GCC" = "xyes"; then
|
||||
AC_EGREP_CPP([AX_PTHREAD_CC_IS_CLANG],
|
||||
[/* Note: Clang 2.7 lacks __clang_[a-z]+__ */
|
||||
# if defined(__clang__) && defined(__llvm__)
|
||||
AX_PTHREAD_CC_IS_CLANG
|
||||
# endif
|
||||
],
|
||||
[ax_cv_PTHREAD_CLANG=yes])
|
||||
fi
|
||||
])
|
||||
ax_pthread_clang="$ax_cv_PTHREAD_CLANG"
|
||||
|
||||
if test x"$ax_pthread_ok" = xno; then
|
||||
for flag in $ax_pthread_flags; do
|
||||
|
||||
case $flag in
|
||||
# GCC generally uses -pthread, or -pthreads on some platforms (e.g. SPARC)
|
||||
|
||||
# Note that for GCC and Clang -pthread generally implies -lpthread,
|
||||
# except when -nostdlib is passed.
|
||||
# This is problematic using libtool to build C++ shared libraries with pthread:
|
||||
# [1] https://gcc.gnu.org/bugzilla/show_bug.cgi?id=25460
|
||||
# [2] https://bugzilla.redhat.com/show_bug.cgi?id=661333
|
||||
# [3] https://bugs.debian.org/cgi-bin/bugreport.cgi?bug=468555
|
||||
# To solve this, first try -pthread together with -lpthread for GCC
|
||||
|
||||
AS_IF([test "x$GCC" = "xyes"],
|
||||
[ax_pthread_flags="-pthread,-lpthread -pthread -pthreads $ax_pthread_flags"])
|
||||
|
||||
# Clang takes -pthread (never supported any other flag), but we'll try with -lpthread first
|
||||
|
||||
AS_IF([test "x$ax_pthread_clang" = "xyes"],
|
||||
[ax_pthread_flags="-pthread,-lpthread -pthread"])
|
||||
|
||||
|
||||
# The presence of a feature test macro requesting re-entrant function
|
||||
# definitions is, on some systems, a strong hint that pthreads support is
|
||||
# correctly enabled
|
||||
|
||||
case $host_os in
|
||||
darwin* | hpux* | linux* | osf* | solaris*)
|
||||
ax_pthread_check_macro="_REENTRANT"
|
||||
;;
|
||||
|
||||
aix*)
|
||||
ax_pthread_check_macro="_THREAD_SAFE"
|
||||
;;
|
||||
|
||||
*)
|
||||
ax_pthread_check_macro="--"
|
||||
;;
|
||||
esac
|
||||
AS_IF([test "x$ax_pthread_check_macro" = "x--"],
|
||||
[ax_pthread_check_cond=0],
|
||||
[ax_pthread_check_cond="!defined($ax_pthread_check_macro)"])
|
||||
|
||||
|
||||
if test "x$ax_pthread_ok" = "xno"; then
|
||||
for ax_pthread_try_flag in $ax_pthread_flags; do
|
||||
|
||||
case $ax_pthread_try_flag in
|
||||
none)
|
||||
AC_MSG_CHECKING([whether pthreads work without any flags])
|
||||
;;
|
||||
|
||||
*,*)
|
||||
PTHREAD_CFLAGS=`echo $ax_pthread_try_flag | sed "s/^\(.*\),\(.*\)$/\1/"`
|
||||
PTHREAD_LIBS=`echo $ax_pthread_try_flag | sed "s/^\(.*\),\(.*\)$/\2/"`
|
||||
AC_MSG_CHECKING([whether pthreads work with "$PTHREAD_CFLAGS" and "$PTHREAD_LIBS"])
|
||||
;;
|
||||
|
||||
-*)
|
||||
AC_MSG_CHECKING([whether pthreads work with $flag])
|
||||
PTHREAD_CFLAGS="$flag"
|
||||
AC_MSG_CHECKING([whether pthreads work with $ax_pthread_try_flag])
|
||||
PTHREAD_CFLAGS="$ax_pthread_try_flag"
|
||||
;;
|
||||
|
||||
pthread-config)
|
||||
AC_CHECK_PROG([ax_pthread_config], [pthread-config], [yes], [no])
|
||||
if test x"$ax_pthread_config" = xno; then continue; fi
|
||||
AS_IF([test "x$ax_pthread_config" = "xno"], [continue])
|
||||
PTHREAD_CFLAGS="`pthread-config --cflags`"
|
||||
PTHREAD_LIBS="`pthread-config --ldflags` `pthread-config --libs`"
|
||||
;;
|
||||
|
||||
*)
|
||||
AC_MSG_CHECKING([for the pthreads library -l$flag])
|
||||
PTHREAD_LIBS="-l$flag"
|
||||
AC_MSG_CHECKING([for the pthreads library -l$ax_pthread_try_flag])
|
||||
PTHREAD_LIBS="-l$ax_pthread_try_flag"
|
||||
;;
|
||||
esac
|
||||
|
||||
save_LIBS="$LIBS"
|
||||
save_CFLAGS="$CFLAGS"
|
||||
ax_pthread_save_CFLAGS="$CFLAGS"
|
||||
ax_pthread_save_LIBS="$LIBS"
|
||||
CFLAGS="$CFLAGS $PTHREAD_CFLAGS"
|
||||
LIBS="$PTHREAD_LIBS $LIBS"
|
||||
CFLAGS="$CFLAGS $PTHREAD_CFLAGS $ax_pthread_extra_flags"
|
||||
|
||||
# Check for various functions. We must include pthread.h,
|
||||
# since some functions may be macros. (On the Sequent, we
|
||||
@@ -218,8 +312,18 @@ for flag in $ax_pthread_flags; do
|
||||
# pthread_cleanup_push because it is one of the few pthread
|
||||
# functions on Solaris that doesn't have a non-functional libc stub.
|
||||
# We try pthread_create on general principles.
|
||||
|
||||
AC_LINK_IFELSE([AC_LANG_PROGRAM([#include <pthread.h>
|
||||
static void routine(void *a) { *((int*)a) = 0; }
|
||||
# if $ax_pthread_check_cond
|
||||
# error "$ax_pthread_check_macro must be defined"
|
||||
# endif
|
||||
static void *some_global = NULL;
|
||||
static void routine(void *a)
|
||||
{
|
||||
/* To avoid any unused-parameter or
|
||||
unused-but-set-parameter warning. */
|
||||
some_global = a;
|
||||
}
|
||||
static void *start_routine(void *a) { return a; }],
|
||||
[pthread_t th; pthread_attr_t attr;
|
||||
pthread_create(&th, 0, start_routine, 0);
|
||||
@@ -227,101 +331,187 @@ for flag in $ax_pthread_flags; do
|
||||
pthread_attr_init(&attr);
|
||||
pthread_cleanup_push(routine, 0);
|
||||
pthread_cleanup_pop(0) /* ; */])],
|
||||
[ax_pthread_ok=yes],
|
||||
[])
|
||||
[ax_pthread_ok=yes],
|
||||
[])
|
||||
|
||||
LIBS="$save_LIBS"
|
||||
CFLAGS="$save_CFLAGS"
|
||||
CFLAGS="$ax_pthread_save_CFLAGS"
|
||||
LIBS="$ax_pthread_save_LIBS"
|
||||
|
||||
AC_MSG_RESULT([$ax_pthread_ok])
|
||||
if test "x$ax_pthread_ok" = xyes; then
|
||||
break;
|
||||
fi
|
||||
AS_IF([test "x$ax_pthread_ok" = "xyes"], [break])
|
||||
|
||||
PTHREAD_LIBS=""
|
||||
PTHREAD_CFLAGS=""
|
||||
done
|
||||
fi
|
||||
|
||||
|
||||
# Clang needs special handling, because older versions handle the -pthread
|
||||
# option in a rather... idiosyncratic way
|
||||
|
||||
if test "x$ax_pthread_clang" = "xyes"; then
|
||||
|
||||
# Clang takes -pthread; it has never supported any other flag
|
||||
|
||||
# (Note 1: This will need to be revisited if a system that Clang
|
||||
# supports has POSIX threads in a separate library. This tends not
|
||||
# to be the way of modern systems, but it's conceivable.)
|
||||
|
||||
# (Note 2: On some systems, notably Darwin, -pthread is not needed
|
||||
# to get POSIX threads support; the API is always present and
|
||||
# active. We could reasonably leave PTHREAD_CFLAGS empty. But
|
||||
# -pthread does define _REENTRANT, and while the Darwin headers
|
||||
# ignore this macro, third-party headers might not.)
|
||||
|
||||
# However, older versions of Clang make a point of warning the user
|
||||
# that, in an invocation where only linking and no compilation is
|
||||
# taking place, the -pthread option has no effect ("argument unused
|
||||
# during compilation"). They expect -pthread to be passed in only
|
||||
# when source code is being compiled.
|
||||
#
|
||||
# Problem is, this is at odds with the way Automake and most other
|
||||
# C build frameworks function, which is that the same flags used in
|
||||
# compilation (CFLAGS) are also used in linking. Many systems
|
||||
# supported by AX_PTHREAD require exactly this for POSIX threads
|
||||
# support, and in fact it is often not straightforward to specify a
|
||||
# flag that is used only in the compilation phase and not in
|
||||
# linking. Such a scenario is extremely rare in practice.
|
||||
#
|
||||
# Even though use of the -pthread flag in linking would only print
|
||||
# a warning, this can be a nuisance for well-run software projects
|
||||
# that build with -Werror. So if the active version of Clang has
|
||||
# this misfeature, we search for an option to squash it.
|
||||
|
||||
AC_CACHE_CHECK([whether Clang needs flag to prevent "argument unused" warning when linking with -pthread],
|
||||
[ax_cv_PTHREAD_CLANG_NO_WARN_FLAG],
|
||||
[ax_cv_PTHREAD_CLANG_NO_WARN_FLAG=unknown
|
||||
# Create an alternate version of $ac_link that compiles and
|
||||
# links in two steps (.c -> .o, .o -> exe) instead of one
|
||||
# (.c -> exe), because the warning occurs only in the second
|
||||
# step
|
||||
ax_pthread_save_ac_link="$ac_link"
|
||||
ax_pthread_sed='s/conftest\.\$ac_ext/conftest.$ac_objext/g'
|
||||
ax_pthread_link_step=`AS_ECHO(["$ac_link"]) | sed "$ax_pthread_sed"`
|
||||
ax_pthread_2step_ac_link="($ac_compile) && (echo ==== >&5) && ($ax_pthread_link_step)"
|
||||
ax_pthread_save_CFLAGS="$CFLAGS"
|
||||
for ax_pthread_try in '' -Qunused-arguments -Wno-unused-command-line-argument unknown; do
|
||||
AS_IF([test "x$ax_pthread_try" = "xunknown"], [break])
|
||||
CFLAGS="-Werror -Wunknown-warning-option $ax_pthread_try -pthread $ax_pthread_save_CFLAGS"
|
||||
ac_link="$ax_pthread_save_ac_link"
|
||||
AC_LINK_IFELSE([AC_LANG_SOURCE([[int main(void){return 0;}]])],
|
||||
[ac_link="$ax_pthread_2step_ac_link"
|
||||
AC_LINK_IFELSE([AC_LANG_SOURCE([[int main(void){return 0;}]])],
|
||||
[break])
|
||||
])
|
||||
done
|
||||
ac_link="$ax_pthread_save_ac_link"
|
||||
CFLAGS="$ax_pthread_save_CFLAGS"
|
||||
AS_IF([test "x$ax_pthread_try" = "x"], [ax_pthread_try=no])
|
||||
ax_cv_PTHREAD_CLANG_NO_WARN_FLAG="$ax_pthread_try"
|
||||
])
|
||||
|
||||
case "$ax_cv_PTHREAD_CLANG_NO_WARN_FLAG" in
|
||||
no | unknown) ;;
|
||||
*) PTHREAD_CFLAGS="$ax_cv_PTHREAD_CLANG_NO_WARN_FLAG $PTHREAD_CFLAGS" ;;
|
||||
esac
|
||||
|
||||
fi # $ax_pthread_clang = yes
|
||||
|
||||
|
||||
|
||||
# Various other checks:
|
||||
if test "x$ax_pthread_ok" = xyes; then
|
||||
save_LIBS="$LIBS"
|
||||
LIBS="$PTHREAD_LIBS $LIBS"
|
||||
save_CFLAGS="$CFLAGS"
|
||||
if test "x$ax_pthread_ok" = "xyes"; then
|
||||
ax_pthread_save_CFLAGS="$CFLAGS"
|
||||
ax_pthread_save_LIBS="$LIBS"
|
||||
CFLAGS="$CFLAGS $PTHREAD_CFLAGS"
|
||||
LIBS="$PTHREAD_LIBS $LIBS"
|
||||
|
||||
# Detect AIX lossage: JOINABLE attribute is called UNDETACHED.
|
||||
AC_MSG_CHECKING([for joinable pthread attribute])
|
||||
attr_name=unknown
|
||||
for attr in PTHREAD_CREATE_JOINABLE PTHREAD_CREATE_UNDETACHED; do
|
||||
AC_LINK_IFELSE([AC_LANG_PROGRAM([#include <pthread.h>],
|
||||
[int attr = $attr; return attr /* ; */])],
|
||||
[attr_name=$attr; break],
|
||||
[])
|
||||
done
|
||||
AC_MSG_RESULT([$attr_name])
|
||||
if test "$attr_name" != PTHREAD_CREATE_JOINABLE; then
|
||||
AC_DEFINE_UNQUOTED([PTHREAD_CREATE_JOINABLE], [$attr_name],
|
||||
[Define to necessary symbol if this constant
|
||||
uses a non-standard name on your system.])
|
||||
fi
|
||||
AC_CACHE_CHECK([for joinable pthread attribute],
|
||||
[ax_cv_PTHREAD_JOINABLE_ATTR],
|
||||
[ax_cv_PTHREAD_JOINABLE_ATTR=unknown
|
||||
for ax_pthread_attr in PTHREAD_CREATE_JOINABLE PTHREAD_CREATE_UNDETACHED; do
|
||||
AC_LINK_IFELSE([AC_LANG_PROGRAM([#include <pthread.h>],
|
||||
[int attr = $ax_pthread_attr; return attr /* ; */])],
|
||||
[ax_cv_PTHREAD_JOINABLE_ATTR=$ax_pthread_attr; break],
|
||||
[])
|
||||
done
|
||||
])
|
||||
AS_IF([test "x$ax_cv_PTHREAD_JOINABLE_ATTR" != "xunknown" && \
|
||||
test "x$ax_cv_PTHREAD_JOINABLE_ATTR" != "xPTHREAD_CREATE_JOINABLE" && \
|
||||
test "x$ax_pthread_joinable_attr_defined" != "xyes"],
|
||||
[AC_DEFINE_UNQUOTED([PTHREAD_CREATE_JOINABLE],
|
||||
[$ax_cv_PTHREAD_JOINABLE_ATTR],
|
||||
[Define to necessary symbol if this constant
|
||||
uses a non-standard name on your system.])
|
||||
ax_pthread_joinable_attr_defined=yes
|
||||
])
|
||||
|
||||
AC_MSG_CHECKING([if more special flags are required for pthreads])
|
||||
flag=no
|
||||
case ${host_os} in
|
||||
aix* | freebsd* | darwin*) flag="-D_THREAD_SAFE";;
|
||||
osf* | hpux*) flag="-D_REENTRANT";;
|
||||
solaris*)
|
||||
if test "$GCC" = "yes"; then
|
||||
flag="-D_REENTRANT"
|
||||
else
|
||||
# TODO: What about Clang on Solaris?
|
||||
flag="-mt -D_REENTRANT"
|
||||
fi
|
||||
;;
|
||||
esac
|
||||
AC_MSG_RESULT([$flag])
|
||||
if test "x$flag" != xno; then
|
||||
PTHREAD_CFLAGS="$flag $PTHREAD_CFLAGS"
|
||||
fi
|
||||
AC_CACHE_CHECK([whether more special flags are required for pthreads],
|
||||
[ax_cv_PTHREAD_SPECIAL_FLAGS],
|
||||
[ax_cv_PTHREAD_SPECIAL_FLAGS=no
|
||||
case $host_os in
|
||||
solaris*)
|
||||
ax_cv_PTHREAD_SPECIAL_FLAGS="-D_POSIX_PTHREAD_SEMANTICS"
|
||||
;;
|
||||
esac
|
||||
])
|
||||
AS_IF([test "x$ax_cv_PTHREAD_SPECIAL_FLAGS" != "xno" && \
|
||||
test "x$ax_pthread_special_flags_added" != "xyes"],
|
||||
[PTHREAD_CFLAGS="$ax_cv_PTHREAD_SPECIAL_FLAGS $PTHREAD_CFLAGS"
|
||||
ax_pthread_special_flags_added=yes])
|
||||
|
||||
AC_CACHE_CHECK([for PTHREAD_PRIO_INHERIT],
|
||||
[ax_cv_PTHREAD_PRIO_INHERIT], [
|
||||
AC_LINK_IFELSE([AC_LANG_PROGRAM([[#include <pthread.h>]],
|
||||
[[int i = PTHREAD_PRIO_INHERIT;]])],
|
||||
[ax_cv_PTHREAD_PRIO_INHERIT=yes],
|
||||
[ax_cv_PTHREAD_PRIO_INHERIT=no])
|
||||
[ax_cv_PTHREAD_PRIO_INHERIT],
|
||||
[AC_LINK_IFELSE([AC_LANG_PROGRAM([[#include <pthread.h>]],
|
||||
[[int i = PTHREAD_PRIO_INHERIT;
|
||||
return i;]])],
|
||||
[ax_cv_PTHREAD_PRIO_INHERIT=yes],
|
||||
[ax_cv_PTHREAD_PRIO_INHERIT=no])
|
||||
])
|
||||
AS_IF([test "x$ax_cv_PTHREAD_PRIO_INHERIT" = "xyes"],
|
||||
[AC_DEFINE([HAVE_PTHREAD_PRIO_INHERIT], [1], [Have PTHREAD_PRIO_INHERIT.])])
|
||||
AS_IF([test "x$ax_cv_PTHREAD_PRIO_INHERIT" = "xyes" && \
|
||||
test "x$ax_pthread_prio_inherit_defined" != "xyes"],
|
||||
[AC_DEFINE([HAVE_PTHREAD_PRIO_INHERIT], [1], [Have PTHREAD_PRIO_INHERIT.])
|
||||
ax_pthread_prio_inherit_defined=yes
|
||||
])
|
||||
|
||||
LIBS="$save_LIBS"
|
||||
CFLAGS="$save_CFLAGS"
|
||||
CFLAGS="$ax_pthread_save_CFLAGS"
|
||||
LIBS="$ax_pthread_save_LIBS"
|
||||
|
||||
# More AIX lossage: compile with *_r variant
|
||||
if test "x$GCC" != xyes; then
|
||||
if test "x$GCC" != "xyes"; then
|
||||
case $host_os in
|
||||
aix*)
|
||||
AS_CASE(["x/$CC"],
|
||||
[x*/c89|x*/c89_128|x*/c99|x*/c99_128|x*/cc|x*/cc128|x*/xlc|x*/xlc_v6|x*/xlc128|x*/xlc128_v6],
|
||||
[#handle absolute path differently from PATH based program lookup
|
||||
AS_CASE(["x$CC"],
|
||||
[x/*],
|
||||
[AS_IF([AS_EXECUTABLE_P([${CC}_r])],[PTHREAD_CC="${CC}_r"])],
|
||||
[AC_CHECK_PROGS([PTHREAD_CC],[${CC}_r],[$CC])])])
|
||||
[x*/c89|x*/c89_128|x*/c99|x*/c99_128|x*/cc|x*/cc128|x*/xlc|x*/xlc_v6|x*/xlc128|x*/xlc128_v6],
|
||||
[#handle absolute path differently from PATH based program lookup
|
||||
AS_CASE(["x$CC"],
|
||||
[x/*],
|
||||
[
|
||||
AS_IF([AS_EXECUTABLE_P([${CC}_r])],[PTHREAD_CC="${CC}_r"])
|
||||
AS_IF([test "x${CXX}" != "x"], [AS_IF([AS_EXECUTABLE_P([${CXX}_r])],[PTHREAD_CXX="${CXX}_r"])])
|
||||
],
|
||||
[
|
||||
AC_CHECK_PROGS([PTHREAD_CC],[${CC}_r],[$CC])
|
||||
AS_IF([test "x${CXX}" != "x"], [AC_CHECK_PROGS([PTHREAD_CXX],[${CXX}_r],[$CXX])])
|
||||
]
|
||||
)
|
||||
])
|
||||
;;
|
||||
esac
|
||||
fi
|
||||
fi
|
||||
|
||||
test -n "$PTHREAD_CC" || PTHREAD_CC="$CC"
|
||||
test -n "$PTHREAD_CXX" || PTHREAD_CXX="$CXX"
|
||||
|
||||
AC_SUBST([PTHREAD_LIBS])
|
||||
AC_SUBST([PTHREAD_CFLAGS])
|
||||
AC_SUBST([PTHREAD_CC])
|
||||
AC_SUBST([PTHREAD_CXX])
|
||||
|
||||
# Finally, execute ACTION-IF-FOUND/ACTION-IF-NOT-FOUND:
|
||||
if test x"$ax_pthread_ok" = xyes; then
|
||||
if test "x$ax_pthread_ok" = "xyes"; then
|
||||
ifelse([$1],,[AC_DEFINE([HAVE_PTHREAD],[1],[Define if you have POSIX threads libraries and header files.])],[$1])
|
||||
:
|
||||
else
|
||||
|
||||
+142
-31
@@ -50,6 +50,8 @@
|
||||
#include "util/data/msgreply.h"
|
||||
#include "util/data/msgencode.h"
|
||||
#include "services/cache/dns.h"
|
||||
#include "services/mesh.h"
|
||||
#include "services/modstack.h"
|
||||
#include "validator/val_neg.h"
|
||||
#include "validator/val_secalgo.h"
|
||||
#include "iterator/iter_utils.h"
|
||||
@@ -265,15 +267,6 @@ cachedb_init(struct module_env* env, int id)
|
||||
return 0;
|
||||
}
|
||||
cachedb_env->enabled = 1;
|
||||
if(env->cfg->serve_expired_reply_ttl)
|
||||
log_warn(
|
||||
"cachedb: serve-expired-reply-ttl is set but not working for data "
|
||||
"originating from the external cache; 0 TLL is used for those.");
|
||||
if(env->cfg->serve_expired_client_timeout)
|
||||
log_warn(
|
||||
"cachedb: serve-expired-client-timeout is set but not working for "
|
||||
"data originating from the external cache; expired data are used "
|
||||
"in the reply without first trying to refresh the data.");
|
||||
return 1;
|
||||
}
|
||||
|
||||
@@ -329,30 +322,30 @@ error_response(struct module_qstate* qstate, int id, int rcode)
|
||||
|
||||
/**
|
||||
* Hash the query name, type, class and dbacess-secret into lookup buffer.
|
||||
* @param qstate: query state with query info
|
||||
* and env->cfg with secret.
|
||||
* @param qinfo: query info
|
||||
* @param env: with env->cfg with secret.
|
||||
* @param buf: returned buffer with hash to lookup
|
||||
* @param len: length of the buffer.
|
||||
*/
|
||||
static void
|
||||
calc_hash(struct module_qstate* qstate, char* buf, size_t len)
|
||||
calc_hash(struct query_info* qinfo, struct module_env* env, char* buf,
|
||||
size_t len)
|
||||
{
|
||||
uint8_t clear[1024];
|
||||
size_t clen = 0;
|
||||
uint8_t hash[CACHEDB_HASHSIZE/8];
|
||||
const char* hex = "0123456789ABCDEF";
|
||||
const char* secret = qstate->env->cfg->cachedb_secret;
|
||||
const char* secret = env->cfg->cachedb_secret;
|
||||
size_t i;
|
||||
|
||||
/* copy the hash info into the clear buffer */
|
||||
if(clen + qstate->qinfo.qname_len < sizeof(clear)) {
|
||||
memmove(clear+clen, qstate->qinfo.qname,
|
||||
qstate->qinfo.qname_len);
|
||||
clen += qstate->qinfo.qname_len;
|
||||
if(clen + qinfo->qname_len < sizeof(clear)) {
|
||||
memmove(clear+clen, qinfo->qname, qinfo->qname_len);
|
||||
clen += qinfo->qname_len;
|
||||
}
|
||||
if(clen + 4 < sizeof(clear)) {
|
||||
uint16_t t = htons(qstate->qinfo.qtype);
|
||||
uint16_t c = htons(qstate->qinfo.qclass);
|
||||
uint16_t t = htons(qinfo->qtype);
|
||||
uint16_t c = htons(qinfo->qclass);
|
||||
memmove(clear+clen, &t, 2);
|
||||
memmove(clear+clen+2, &c, 2);
|
||||
clen += 4;
|
||||
@@ -511,9 +504,38 @@ adjust_msg_ttl(struct dns_msg* msg, time_t adjust)
|
||||
}
|
||||
}
|
||||
|
||||
/* Set the TTL of the given RRset to fixed value. */
|
||||
static void
|
||||
packed_rrset_ttl_set(struct packed_rrset_data* data, time_t ttl)
|
||||
{
|
||||
size_t i;
|
||||
size_t total = data->count + data->rrsig_count;
|
||||
data->ttl = ttl;
|
||||
for(i=0; i<total; i++) {
|
||||
data->rr_ttl[i] = ttl;
|
||||
}
|
||||
data->ttl_add = 0;
|
||||
}
|
||||
|
||||
/* Set the TTL of a DNS message and its RRs by to a fixed value. */
|
||||
static void
|
||||
set_msg_ttl(struct dns_msg* msg, time_t ttl)
|
||||
{
|
||||
size_t i;
|
||||
msg->rep->ttl = ttl;
|
||||
msg->rep->prefetch_ttl = PREFETCH_TTL_CALC(msg->rep->ttl);
|
||||
msg->rep->serve_expired_ttl = msg->rep->ttl + SERVE_EXPIRED_TTL;
|
||||
|
||||
for(i=0; i<msg->rep->rrset_count; i++) {
|
||||
packed_rrset_ttl_set((struct packed_rrset_data*)msg->
|
||||
rep->rrsets[i]->entry.data, ttl);
|
||||
}
|
||||
}
|
||||
|
||||
/** convert dns message in buffer to return_msg */
|
||||
static int
|
||||
parse_data(struct module_qstate* qstate, struct sldns_buffer* buf)
|
||||
parse_data(struct module_qstate* qstate, struct sldns_buffer* buf,
|
||||
int* msg_expired)
|
||||
{
|
||||
struct msg_parse* prs;
|
||||
struct edns_data edns;
|
||||
@@ -583,6 +605,7 @@ parse_data(struct module_qstate* qstate, struct sldns_buffer* buf)
|
||||
adjust = *qstate->env->now - (time_t)timestamp;
|
||||
if(qstate->return_msg->rep->ttl < adjust) {
|
||||
verbose(VERB_ALGO, "cachedb msg expired");
|
||||
*msg_expired = 1;
|
||||
/* If serve-expired is enabled, we still use an expired message
|
||||
* setting the TTL to 0. */
|
||||
if(!qstate->env->cfg->serve_expired ||
|
||||
@@ -605,6 +628,7 @@ parse_data(struct module_qstate* qstate, struct sldns_buffer* buf)
|
||||
* 'now' should be redundant given how these values were calculated,
|
||||
* but we check it just in case as does good_expiry_and_qinfo(). */
|
||||
if(qstate->env->cfg->serve_expired &&
|
||||
!qstate->env->cfg->serve_expired_client_timeout &&
|
||||
(adjust == -1 || (time_t)expiry < *qstate->env->now)) {
|
||||
qstate->need_refetch = 1;
|
||||
}
|
||||
@@ -617,10 +641,11 @@ parse_data(struct module_qstate* qstate, struct sldns_buffer* buf)
|
||||
* return true if lookup was successful.
|
||||
*/
|
||||
static int
|
||||
cachedb_extcache_lookup(struct module_qstate* qstate, struct cachedb_env* ie)
|
||||
cachedb_extcache_lookup(struct module_qstate* qstate, struct cachedb_env* ie,
|
||||
int* msg_expired)
|
||||
{
|
||||
char key[(CACHEDB_HASHSIZE/8)*2+1];
|
||||
calc_hash(qstate, key, sizeof(key));
|
||||
calc_hash(&qstate->qinfo, qstate->env, key, sizeof(key));
|
||||
|
||||
/* call backend to fetch data for key into scratch buffer */
|
||||
if( !(*ie->backend->lookup)(qstate->env, ie, key,
|
||||
@@ -634,7 +659,7 @@ cachedb_extcache_lookup(struct module_qstate* qstate, struct cachedb_env* ie)
|
||||
}
|
||||
|
||||
/* parse dns message into return_msg */
|
||||
if( !parse_data(qstate, qstate->env->scratch_buffer) ) {
|
||||
if( !parse_data(qstate, qstate->env->scratch_buffer, msg_expired) ) {
|
||||
return 0;
|
||||
}
|
||||
return 1;
|
||||
@@ -647,7 +672,7 @@ static void
|
||||
cachedb_extcache_store(struct module_qstate* qstate, struct cachedb_env* ie)
|
||||
{
|
||||
char key[(CACHEDB_HASHSIZE/8)*2+1];
|
||||
calc_hash(qstate, key, sizeof(key));
|
||||
calc_hash(&qstate->qinfo, qstate->env, key, sizeof(key));
|
||||
|
||||
/* prepare data in scratch buffer */
|
||||
if(!prep_data(qstate, qstate->env->scratch_buffer))
|
||||
@@ -666,6 +691,7 @@ cachedb_extcache_store(struct module_qstate* qstate, struct cachedb_env* ie)
|
||||
static int
|
||||
cachedb_intcache_lookup(struct module_qstate* qstate, struct cachedb_env* cde)
|
||||
{
|
||||
uint8_t dpname_storage[LDNS_MAX_DOMAINLEN+1];
|
||||
uint8_t* dpname=NULL;
|
||||
size_t dpnamelen=0;
|
||||
struct dns_msg* msg;
|
||||
@@ -674,7 +700,7 @@ cachedb_intcache_lookup(struct module_qstate* qstate, struct cachedb_env* cde)
|
||||
return 0;
|
||||
}
|
||||
if(iter_stub_fwd_no_cache(qstate, &qstate->qinfo,
|
||||
&dpname, &dpnamelen))
|
||||
&dpname, &dpnamelen, dpname_storage, sizeof(dpname_storage)))
|
||||
return 0; /* no cache for these queries */
|
||||
msg = dns_cache_lookup(qstate->env, qstate->qinfo.qname,
|
||||
qstate->qinfo.qname_len, qstate->qinfo.qtype,
|
||||
@@ -705,17 +731,43 @@ cachedb_intcache_lookup(struct module_qstate* qstate, struct cachedb_env* cde)
|
||||
* Store query into the internal cache of unbound.
|
||||
*/
|
||||
static void
|
||||
cachedb_intcache_store(struct module_qstate* qstate)
|
||||
cachedb_intcache_store(struct module_qstate* qstate, int msg_expired)
|
||||
{
|
||||
uint32_t store_flags = qstate->query_flags;
|
||||
int serve_expired = qstate->env->cfg->serve_expired;
|
||||
|
||||
if(qstate->env->cfg->serve_expired)
|
||||
store_flags |= DNSCACHE_STORE_ZEROTTL;
|
||||
if(!qstate->return_msg)
|
||||
return;
|
||||
if(serve_expired && msg_expired) {
|
||||
/* Set TTLs to a value such that value + *env->now is
|
||||
* going to be now-3 seconds. Making it expired
|
||||
* in the cache. */
|
||||
set_msg_ttl(qstate->return_msg, (time_t)-3);
|
||||
/* The expired entry does not get checked by the validator
|
||||
* and we need a validation value for it. */
|
||||
if(qstate->env->cfg->cachedb_check_when_serve_expired)
|
||||
qstate->return_msg->rep->security = sec_status_insecure;
|
||||
}
|
||||
(void)dns_cache_store(qstate->env, &qstate->qinfo,
|
||||
qstate->return_msg->rep, 0, qstate->prefetch_leeway, 0,
|
||||
qstate->region, store_flags, qstate->qstarttime);
|
||||
if(serve_expired && msg_expired) {
|
||||
if(qstate->env->cfg->serve_expired_client_timeout) {
|
||||
/* No expired response from the query state, the
|
||||
* query resolution needs to continue and it can
|
||||
* pick up the expired result after the timer out
|
||||
* of cache. */
|
||||
return;
|
||||
}
|
||||
/* set TTLs to zero again */
|
||||
adjust_msg_ttl(qstate->return_msg, -1);
|
||||
/* Send serve expired responses based on the cachedb
|
||||
* returned message, that was just stored in the cache.
|
||||
* It can then continue to work on this query. */
|
||||
mesh_respond_serve_expired(qstate->mesh_info);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -731,6 +783,7 @@ cachedb_handle_query(struct module_qstate* qstate,
|
||||
struct cachedb_qstate* ATTR_UNUSED(iq),
|
||||
struct cachedb_env* ie, int id)
|
||||
{
|
||||
int msg_expired = 0;
|
||||
qstate->is_cachedb_answer = 0;
|
||||
/* check if we are enabled, and skip if so */
|
||||
if(!ie->enabled) {
|
||||
@@ -765,20 +818,28 @@ cachedb_handle_query(struct module_qstate* qstate,
|
||||
}
|
||||
|
||||
/* ask backend cache to see if we have data */
|
||||
if(cachedb_extcache_lookup(qstate, ie)) {
|
||||
if(cachedb_extcache_lookup(qstate, ie, &msg_expired)) {
|
||||
if(verbosity >= VERB_ALGO)
|
||||
log_dns_msg(ie->backend->name,
|
||||
&qstate->return_msg->qinfo,
|
||||
qstate->return_msg->rep);
|
||||
/* store this result in internal cache */
|
||||
cachedb_intcache_store(qstate);
|
||||
cachedb_intcache_store(qstate, msg_expired);
|
||||
/* In case we have expired data but there is a client timer for expired
|
||||
* answers, pass execution to next module in order to try updating the
|
||||
* data first.
|
||||
* TODO: this needs revisit. The expired data stored from cachedb has
|
||||
* 0 TTL which is picked up by iterator later when looking in the cache.
|
||||
* Document that ext cachedb does not work properly with
|
||||
* serve_stale_reply_ttl yet. */
|
||||
*/
|
||||
if(qstate->env->cfg->serve_expired && msg_expired) {
|
||||
qstate->return_msg = NULL;
|
||||
qstate->ext_state[id] = module_wait_module;
|
||||
/* The expired reply is sent with
|
||||
* mesh_respond_serve_expired, and so
|
||||
* the need_refetch is not used. */
|
||||
qstate->need_refetch = 0;
|
||||
return;
|
||||
}
|
||||
if(qstate->need_refetch && qstate->serve_expired_data &&
|
||||
qstate->serve_expired_data->timer) {
|
||||
qstate->return_msg = NULL;
|
||||
@@ -791,6 +852,14 @@ cachedb_handle_query(struct module_qstate* qstate,
|
||||
return;
|
||||
}
|
||||
|
||||
if(qstate->serve_expired_data &&
|
||||
qstate->env->cfg->cachedb_check_when_serve_expired &&
|
||||
!qstate->env->cfg->serve_expired_client_timeout) {
|
||||
/* Reply with expired data if any to client, because cachedb
|
||||
* also has no useful, current data */
|
||||
mesh_respond_serve_expired(qstate->mesh_info);
|
||||
}
|
||||
|
||||
/* no cache fetches */
|
||||
/* pass request to next module */
|
||||
qstate->ext_state[id] = module_wait_module;
|
||||
@@ -815,6 +884,11 @@ cachedb_handle_response(struct module_qstate* qstate,
|
||||
qstate->ext_state[id] = module_finished;
|
||||
return;
|
||||
}
|
||||
if(qstate->env->cfg->cachedb_no_store) {
|
||||
/* do not store the item in the external cache */
|
||||
qstate->ext_state[id] = module_finished;
|
||||
return;
|
||||
}
|
||||
|
||||
/* store the item into the backend cache */
|
||||
cachedb_extcache_store(qstate, ie);
|
||||
@@ -909,7 +983,7 @@ cachedb_get_mem(struct module_env* env, int id)
|
||||
*/
|
||||
static struct module_func_block cachedb_block = {
|
||||
"cachedb",
|
||||
&cachedb_init, &cachedb_deinit, &cachedb_operate,
|
||||
NULL, NULL, &cachedb_init, &cachedb_deinit, &cachedb_operate,
|
||||
&cachedb_inform_super, &cachedb_clear, &cachedb_get_mem
|
||||
};
|
||||
|
||||
@@ -918,4 +992,41 @@ cachedb_get_funcblock(void)
|
||||
{
|
||||
return &cachedb_block;
|
||||
}
|
||||
|
||||
int
|
||||
cachedb_is_enabled(struct module_stack* mods, struct module_env* env)
|
||||
{
|
||||
struct cachedb_env* ie;
|
||||
int id = modstack_find(mods, "cachedb");
|
||||
if(id == -1)
|
||||
return 0;
|
||||
ie = (struct cachedb_env*)env->modinfo[id];
|
||||
if(ie && ie->enabled)
|
||||
return 1;
|
||||
return 0;
|
||||
}
|
||||
|
||||
void cachedb_msg_remove(struct module_qstate* qstate)
|
||||
{
|
||||
cachedb_msg_remove_qinfo(qstate->env, &qstate->qinfo);
|
||||
}
|
||||
|
||||
void cachedb_msg_remove_qinfo(struct module_env* env, struct query_info* qinfo)
|
||||
{
|
||||
char key[(CACHEDB_HASHSIZE/8)*2+1];
|
||||
int id = modstack_find(env->modstack, "cachedb");
|
||||
struct cachedb_env* ie = (struct cachedb_env*)env->modinfo[id];
|
||||
|
||||
log_query_info(VERB_ALGO, "cachedb msg remove", qinfo);
|
||||
calc_hash(qinfo, env, key, sizeof(key));
|
||||
sldns_buffer_clear(env->scratch_buffer);
|
||||
sldns_buffer_write_u32(env->scratch_buffer, 0);
|
||||
sldns_buffer_flip(env->scratch_buffer);
|
||||
|
||||
/* call backend */
|
||||
(*ie->backend->store)(env, ie, key,
|
||||
sldns_buffer_begin(env->scratch_buffer),
|
||||
sldns_buffer_limit(env->scratch_buffer),
|
||||
0);
|
||||
}
|
||||
#endif /* USE_CACHEDB */
|
||||
|
||||
@@ -41,6 +41,7 @@
|
||||
*/
|
||||
#include "util/module.h"
|
||||
struct cachedb_backend;
|
||||
struct module_stack;
|
||||
|
||||
/**
|
||||
* The global variable environment contents for the cachedb
|
||||
@@ -110,3 +111,26 @@ size_t cachedb_get_mem(struct module_env* env, int id);
|
||||
*/
|
||||
struct module_func_block* cachedb_get_funcblock(void);
|
||||
|
||||
/**
|
||||
* See if the cachedb is enabled.
|
||||
* @param mods: module stack. It finds the cachedb module environment.
|
||||
* @param env: module environment.
|
||||
* @return true if exists and enabled.
|
||||
*/
|
||||
int cachedb_is_enabled(struct module_stack* mods, struct module_env* env);
|
||||
|
||||
/**
|
||||
* Remove a message from the global cache. Because edns subnet has a more
|
||||
* specific entry, and if not removed when everything expires, the global
|
||||
* entry is used, instead of a fresh lookup of the edns subnet entry.
|
||||
* @param qstate: query state.
|
||||
*/
|
||||
void cachedb_msg_remove(struct module_qstate* qstate);
|
||||
|
||||
/**
|
||||
* Remove message from the cachedb cache, by query info.
|
||||
* @param env: module environment to look up cachedb state.
|
||||
* @param qinfo: the message to remove.
|
||||
*/
|
||||
void cachedb_msg_remove_qinfo(struct module_env* env,
|
||||
struct query_info* qinfo);
|
||||
|
||||
+47
-21
@@ -59,11 +59,28 @@ struct redis_moddata {
|
||||
const char* server_path; /* server's unix path, or "", NULL if unused */
|
||||
const char* server_password; /* server's AUTH password, or "", NULL if unused */
|
||||
struct timeval timeout; /* timeout for connection setup and commands */
|
||||
int logical_db; /* the redis logical database to use */
|
||||
};
|
||||
|
||||
static redisReply* redis_command(struct module_env*, struct cachedb_env*,
|
||||
const char*, const uint8_t*, size_t);
|
||||
|
||||
static void
|
||||
moddata_clean(struct redis_moddata** moddata) {
|
||||
if(!moddata || !*moddata)
|
||||
return;
|
||||
if((*moddata)->ctxs) {
|
||||
int i;
|
||||
for(i = 0; i < (*moddata)->numctxs; i++) {
|
||||
if((*moddata)->ctxs[i])
|
||||
redisFree((*moddata)->ctxs[i]);
|
||||
}
|
||||
free((*moddata)->ctxs);
|
||||
}
|
||||
free(*moddata);
|
||||
*moddata = NULL;
|
||||
}
|
||||
|
||||
static redisContext*
|
||||
redis_connect(const struct redis_moddata* moddata)
|
||||
{
|
||||
@@ -97,10 +114,21 @@ redis_connect(const struct redis_moddata* moddata)
|
||||
}
|
||||
freeReplyObject(rep);
|
||||
}
|
||||
if(moddata->logical_db > 0) {
|
||||
redisReply* rep;
|
||||
rep = redisCommand(ctx, "SELECT %d", moddata->logical_db);
|
||||
if(!rep || rep->type == REDIS_REPLY_ERROR) {
|
||||
log_err("failed to set logical database (%d)",
|
||||
moddata->logical_db);
|
||||
freeReplyObject(rep);
|
||||
goto fail;
|
||||
}
|
||||
freeReplyObject(rep);
|
||||
}
|
||||
verbose(VERB_OPS, "Connection to Redis established");
|
||||
return ctx;
|
||||
|
||||
fail:
|
||||
fail:
|
||||
if(ctx)
|
||||
redisFree(ctx);
|
||||
return NULL;
|
||||
@@ -117,14 +145,13 @@ redis_init(struct module_env* env, struct cachedb_env* cachedb_env)
|
||||
moddata = calloc(1, sizeof(struct redis_moddata));
|
||||
if(!moddata) {
|
||||
log_err("out of memory");
|
||||
return 0;
|
||||
goto fail;
|
||||
}
|
||||
moddata->numctxs = env->cfg->num_threads;
|
||||
moddata->ctxs = calloc(env->cfg->num_threads, sizeof(redisContext*));
|
||||
if(!moddata->ctxs) {
|
||||
log_err("out of memory");
|
||||
free(moddata);
|
||||
return 0;
|
||||
goto fail;
|
||||
}
|
||||
/* note: server_host is a shallow reference to configured string.
|
||||
* we don't have to free it in this module. */
|
||||
@@ -134,8 +161,15 @@ redis_init(struct module_env* env, struct cachedb_env* cachedb_env)
|
||||
moddata->server_password = env->cfg->redis_server_password;
|
||||
moddata->timeout.tv_sec = env->cfg->redis_timeout / 1000;
|
||||
moddata->timeout.tv_usec = (env->cfg->redis_timeout % 1000) * 1000;
|
||||
for(i = 0; i < moddata->numctxs; i++)
|
||||
moddata->ctxs[i] = redis_connect(moddata);
|
||||
moddata->logical_db = env->cfg->redis_logical_db;
|
||||
for(i = 0; i < moddata->numctxs; i++) {
|
||||
redisContext* ctx = redis_connect(moddata);
|
||||
if(!ctx) {
|
||||
log_err("redis_init: failed to init redis");
|
||||
goto fail;
|
||||
}
|
||||
moddata->ctxs[i] = ctx;
|
||||
}
|
||||
cachedb_env->backend_data = moddata;
|
||||
if(env->cfg->redis_expire_records) {
|
||||
redisReply* rep = NULL;
|
||||
@@ -148,7 +182,7 @@ redis_init(struct module_env* env, struct cachedb_env* cachedb_env)
|
||||
log_err("redis_init: failed to init redis, the "
|
||||
"redis-expire-records option requires the SETEX command "
|
||||
"(redis >= 2.0.0)");
|
||||
return 0;
|
||||
goto fail;
|
||||
}
|
||||
redis_reply_type = rep->type;
|
||||
freeReplyObject(rep);
|
||||
@@ -160,11 +194,14 @@ redis_init(struct module_env* env, struct cachedb_env* cachedb_env)
|
||||
log_err("redis_init: failed to init redis, the "
|
||||
"redis-expire-records option requires the SETEX command "
|
||||
"(redis >= 2.0.0)");
|
||||
return 0;
|
||||
goto fail;
|
||||
}
|
||||
}
|
||||
|
||||
return 1;
|
||||
|
||||
fail:
|
||||
moddata_clean(&moddata);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void
|
||||
@@ -175,18 +212,7 @@ redis_deinit(struct module_env* env, struct cachedb_env* cachedb_env)
|
||||
(void)env;
|
||||
|
||||
verbose(VERB_OPS, "Redis deinitialization");
|
||||
|
||||
if(!moddata)
|
||||
return;
|
||||
if(moddata->ctxs) {
|
||||
int i;
|
||||
for(i = 0; i < moddata->numctxs; i++) {
|
||||
if(moddata->ctxs[i])
|
||||
redisFree(moddata->ctxs[i]);
|
||||
}
|
||||
free(moddata->ctxs);
|
||||
}
|
||||
free(moddata);
|
||||
moddata_clean(&moddata);
|
||||
}
|
||||
|
||||
/*
|
||||
|
||||
Vendored
+704
-559
File diff suppressed because it is too large
Load Diff
+88
-23
@@ -379,8 +379,8 @@
|
||||
/* Define to 1 if you have the `memmove' function. */
|
||||
#undef HAVE_MEMMOVE
|
||||
|
||||
/* Define to 1 if you have the <memory.h> header file. */
|
||||
#undef HAVE_MEMORY_H
|
||||
/* Define to 1 if you have the <minix/config.h> header file. */
|
||||
#undef HAVE_MINIX_CONFIG_H
|
||||
|
||||
/* Define to 1 if you have the <netdb.h> header file. */
|
||||
#undef HAVE_NETDB_H
|
||||
@@ -406,6 +406,9 @@
|
||||
/* Define to 1 if you have the <net/if.h> header file. */
|
||||
#undef HAVE_NET_IF_H
|
||||
|
||||
/* Define to 1 if you have the <net/pfvar.h> header file. */
|
||||
#undef HAVE_NET_PFVAR_H
|
||||
|
||||
/* Define this to use nghttp2 client. */
|
||||
#undef HAVE_NGHTTP2
|
||||
|
||||
@@ -566,6 +569,9 @@
|
||||
function. */
|
||||
#undef HAVE_SSL_CTX_SET_TLSEXT_TICKET_KEY_EVP_CB
|
||||
|
||||
/* Define to 1 if you have the `SSL_CTX_set_tmp_ecdh' function. */
|
||||
#undef HAVE_SSL_CTX_SET_TMP_ECDH
|
||||
|
||||
/* Define to 1 if you have the `SSL_get0_alpn_selected' function. */
|
||||
#undef HAVE_SSL_GET0_ALPN_SELECTED
|
||||
|
||||
@@ -587,6 +593,9 @@
|
||||
/* Define to 1 if you have the <stdint.h> header file. */
|
||||
#undef HAVE_STDINT_H
|
||||
|
||||
/* Define to 1 if you have the <stdio.h> header file. */
|
||||
#undef HAVE_STDIO_H
|
||||
|
||||
/* Define to 1 if you have the <stdlib.h> header file. */
|
||||
#undef HAVE_STDLIB_H
|
||||
|
||||
@@ -689,6 +698,9 @@
|
||||
/* Define to 1 if you have the <vfork.h> header file. */
|
||||
#undef HAVE_VFORK_H
|
||||
|
||||
/* Define to 1 if you have the <wchar.h> header file. */
|
||||
#undef HAVE_WCHAR_H
|
||||
|
||||
/* Define to 1 if you have the <windows.h> header file. */
|
||||
#undef HAVE_WINDOWS_H
|
||||
|
||||
@@ -830,7 +842,9 @@
|
||||
/* Define to 1 if libsodium supports sodium_set_misuse_handler */
|
||||
#undef SODIUM_MISUSE_HANDLER
|
||||
|
||||
/* Define to 1 if you have the ANSI C header files. */
|
||||
/* Define to 1 if all of the C90 standard headers exist (not just the ones
|
||||
required in a freestanding environment). This macro is provided for
|
||||
backward compatibility; new code need not use it. */
|
||||
#undef STDC_HEADERS
|
||||
|
||||
/* use default strptime. */
|
||||
@@ -926,21 +940,87 @@
|
||||
#ifndef _ALL_SOURCE
|
||||
# undef _ALL_SOURCE
|
||||
#endif
|
||||
/* Enable general extensions on macOS. */
|
||||
#ifndef _DARWIN_C_SOURCE
|
||||
# undef _DARWIN_C_SOURCE
|
||||
#endif
|
||||
/* Enable general extensions on Solaris. */
|
||||
#ifndef __EXTENSIONS__
|
||||
# undef __EXTENSIONS__
|
||||
#endif
|
||||
/* Enable GNU extensions on systems that have them. */
|
||||
#ifndef _GNU_SOURCE
|
||||
# undef _GNU_SOURCE
|
||||
#endif
|
||||
/* Enable threading extensions on Solaris. */
|
||||
/* Enable X/Open compliant socket functions that do not require linking
|
||||
with -lxnet on HP-UX 11.11. */
|
||||
#ifndef _HPUX_ALT_XOPEN_SOCKET_API
|
||||
# undef _HPUX_ALT_XOPEN_SOCKET_API
|
||||
#endif
|
||||
/* Identify the host operating system as Minix.
|
||||
This macro does not affect the system headers' behavior.
|
||||
A future release of Autoconf may stop defining this macro. */
|
||||
#ifndef _MINIX
|
||||
# undef _MINIX
|
||||
#endif
|
||||
/* Enable general extensions on NetBSD.
|
||||
Enable NetBSD compatibility extensions on Minix. */
|
||||
#ifndef _NETBSD_SOURCE
|
||||
# undef _NETBSD_SOURCE
|
||||
#endif
|
||||
/* Enable OpenBSD compatibility extensions on NetBSD.
|
||||
Oddly enough, this does nothing on OpenBSD. */
|
||||
#ifndef _OPENBSD_SOURCE
|
||||
# undef _OPENBSD_SOURCE
|
||||
#endif
|
||||
/* Define to 1 if needed for POSIX-compatible behavior. */
|
||||
#ifndef _POSIX_SOURCE
|
||||
# undef _POSIX_SOURCE
|
||||
#endif
|
||||
/* Define to 2 if needed for POSIX-compatible behavior. */
|
||||
#ifndef _POSIX_1_SOURCE
|
||||
# undef _POSIX_1_SOURCE
|
||||
#endif
|
||||
/* Enable POSIX-compatible threading on Solaris. */
|
||||
#ifndef _POSIX_PTHREAD_SEMANTICS
|
||||
# undef _POSIX_PTHREAD_SEMANTICS
|
||||
#endif
|
||||
/* Enable extensions specified by ISO/IEC TS 18661-5:2014. */
|
||||
#ifndef __STDC_WANT_IEC_60559_ATTRIBS_EXT__
|
||||
# undef __STDC_WANT_IEC_60559_ATTRIBS_EXT__
|
||||
#endif
|
||||
/* Enable extensions specified by ISO/IEC TS 18661-1:2014. */
|
||||
#ifndef __STDC_WANT_IEC_60559_BFP_EXT__
|
||||
# undef __STDC_WANT_IEC_60559_BFP_EXT__
|
||||
#endif
|
||||
/* Enable extensions specified by ISO/IEC TS 18661-2:2015. */
|
||||
#ifndef __STDC_WANT_IEC_60559_DFP_EXT__
|
||||
# undef __STDC_WANT_IEC_60559_DFP_EXT__
|
||||
#endif
|
||||
/* Enable extensions specified by ISO/IEC TS 18661-4:2015. */
|
||||
#ifndef __STDC_WANT_IEC_60559_FUNCS_EXT__
|
||||
# undef __STDC_WANT_IEC_60559_FUNCS_EXT__
|
||||
#endif
|
||||
/* Enable extensions specified by ISO/IEC TS 18661-3:2015. */
|
||||
#ifndef __STDC_WANT_IEC_60559_TYPES_EXT__
|
||||
# undef __STDC_WANT_IEC_60559_TYPES_EXT__
|
||||
#endif
|
||||
/* Enable extensions specified by ISO/IEC TR 24731-2:2010. */
|
||||
#ifndef __STDC_WANT_LIB_EXT2__
|
||||
# undef __STDC_WANT_LIB_EXT2__
|
||||
#endif
|
||||
/* Enable extensions specified by ISO/IEC 24747:2009. */
|
||||
#ifndef __STDC_WANT_MATH_SPEC_FUNCS__
|
||||
# undef __STDC_WANT_MATH_SPEC_FUNCS__
|
||||
#endif
|
||||
/* Enable extensions on HP NonStop. */
|
||||
#ifndef _TANDEM_SOURCE
|
||||
# undef _TANDEM_SOURCE
|
||||
#endif
|
||||
/* Enable general extensions on Solaris. */
|
||||
#ifndef __EXTENSIONS__
|
||||
# undef __EXTENSIONS__
|
||||
/* Enable X/Open extensions. Define to 500 only if necessary
|
||||
to make mbstate_t available. */
|
||||
#ifndef _XOPEN_SOURCE
|
||||
# undef _XOPEN_SOURCE
|
||||
#endif
|
||||
|
||||
|
||||
@@ -966,11 +1046,6 @@
|
||||
`char[]'. */
|
||||
#undef YYTEXT_POINTER
|
||||
|
||||
/* Enable large inode numbers on Mac OS X 10.5. */
|
||||
#ifndef _DARWIN_USE_64_BIT_INODE
|
||||
# define _DARWIN_USE_64_BIT_INODE 1
|
||||
#endif
|
||||
|
||||
/* Number of bits in a file offset, on hosts where this is settable. */
|
||||
#undef _FILE_OFFSET_BITS
|
||||
|
||||
@@ -980,19 +1055,9 @@
|
||||
/* Define for large files, on AIX-style hosts. */
|
||||
#undef _LARGE_FILES
|
||||
|
||||
/* Define to 1 if on MINIX. */
|
||||
#undef _MINIX
|
||||
|
||||
/* Enable for compile on Minix */
|
||||
#undef _NETBSD_SOURCE
|
||||
|
||||
/* Define to 2 if the system does not provide POSIX.1 features except with
|
||||
this defined. */
|
||||
#undef _POSIX_1_SOURCE
|
||||
|
||||
/* Define to 1 if you need to in order for `stat' and other things to work. */
|
||||
#undef _POSIX_SOURCE
|
||||
|
||||
/* defined to use gcc ansi snprintf and sscanf that understands %lld when
|
||||
compiled for windows. */
|
||||
#undef __USE_MINGW_ANSI_STDIO
|
||||
@@ -1033,7 +1098,7 @@
|
||||
/* Define to `long int' if <sys/types.h> does not define. */
|
||||
#undef off_t
|
||||
|
||||
/* Define to `int' if <sys/types.h> does not define. */
|
||||
/* Define as a signed integer type capable of holding a process identifier. */
|
||||
#undef pid_t
|
||||
|
||||
/* Define to 'int' if not defined */
|
||||
|
||||
Vendored
+503
-325
File diff suppressed because it is too large
Load Diff
+68
-30
@@ -4,21 +4,21 @@ AC_PREREQ([2.56])
|
||||
sinclude(acx_nlnetlabs.m4)
|
||||
sinclude(ax_pthread.m4)
|
||||
sinclude(acx_python.m4)
|
||||
sinclude(ac_pkg_swig.m4)
|
||||
sinclude(ax_pkg_swig.m4)
|
||||
sinclude(dnstap/dnstap.m4)
|
||||
sinclude(dnscrypt/dnscrypt.m4)
|
||||
|
||||
# must be numbers. ac_defun because of later processing
|
||||
m4_define([VERSION_MAJOR],[1])
|
||||
m4_define([VERSION_MINOR],[18])
|
||||
m4_define([VERSION_MICRO],[0])
|
||||
m4_define([VERSION_MINOR],[20])
|
||||
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=22
|
||||
LIBUNBOUND_REVISION=28
|
||||
LIBUNBOUND_AGE=1
|
||||
# 1.0.0 had 0:12:0
|
||||
# 1.0.1 had 0:13:0
|
||||
@@ -108,6 +108,12 @@ LIBUNBOUND_AGE=1
|
||||
# 1.17.0 had 9:20:1
|
||||
# 1.17.1 had 9:21:1
|
||||
# 1.18.0 had 9:22:1
|
||||
# 1.19.0 had 9:23:1
|
||||
# 1.19.1 had 9:24:1
|
||||
# 1.19.2 had 9:25:1
|
||||
# 1.19.3 had 9:26:1
|
||||
# 1.20.0 had 9:27:1
|
||||
# 1.20.1 had 9:28:1
|
||||
|
||||
# Current -- the number of the binary API that we're implementing
|
||||
# Revision -- which iteration of the implementation of the binary
|
||||
@@ -269,6 +275,9 @@ AC_DEFINE(WINVER, 0x0502, [the version of the windows API enabled])
|
||||
ACX_RSRC_VERSION(wnvs)
|
||||
AC_DEFINE_UNQUOTED(RSRC_PACKAGE_VERSION, [$wnvs], [version number for resource files])
|
||||
|
||||
# Check for 'grep -e' program, here, since ACX_CHECK_FLTO needs that.
|
||||
AC_PROG_GREP
|
||||
|
||||
# Checks for typedefs, structures, and compiler characteristics.
|
||||
AC_C_CONST
|
||||
AC_LANG([C])
|
||||
@@ -279,7 +288,7 @@ ACX_CHECK_COMPILER_FLAG(g, [CFLAGS="$CFLAGS -g"])
|
||||
ACX_CHECK_COMPILER_FLAG(O2, [CFLAGS="$CFLAGS -O2"])
|
||||
default_cflags=yes
|
||||
fi
|
||||
AC_PROG_CC
|
||||
m4_version_prereq([2.70], [AC_PROG_CC], [AC_PROG_CC_STDC])
|
||||
ACX_DEPFLAG
|
||||
ACX_DETERMINE_EXT_FLAGS_UNBOUND
|
||||
|
||||
@@ -405,7 +414,7 @@ AC_CHECK_TOOL(STRIP, strip)
|
||||
ACX_LIBTOOL_C_ONLY
|
||||
|
||||
# pkg-config is only needed for these options, do not require it otherwise
|
||||
if test "$enable_systemd" = "yes" -o "$with_pyunbound" = "yes" -o "$with_pythonmod" = "yes"; then
|
||||
if test "$enable_systemd" = "yes" -o "$enable_dnstap" = "yes" -o "$with_pyunbound" = "yes" -o "$with_pythonmod" = "yes"; then
|
||||
PKG_PROG_PKG_CONFIG
|
||||
fi
|
||||
|
||||
@@ -525,7 +534,8 @@ res = strptime("2010-07-15T00:00:00+00:00", "%t%Y%t-%t%m%t-%t%d%tT%t%H%t:%t%M%t:
|
||||
if (!res) return 2;
|
||||
res = strptime("20070207111842", "%Y%m%d%H%M%S", &tm);
|
||||
if (!res) return 1; return 0; }
|
||||
]])] , [eval "ac_cv_c_strptime_works=yes"], [eval "ac_cv_c_strptime_works=no"])
|
||||
]])] , [eval "ac_cv_c_strptime_works=yes"], [eval "ac_cv_c_strptime_works=no"],
|
||||
[eval "ac_cv_c_strptime_works=maybe"])
|
||||
else
|
||||
eval "ac_cv_c_strptime_works=maybe"
|
||||
fi
|
||||
@@ -790,9 +800,9 @@ if test x_$ub_test_python != x_no; then
|
||||
ub_have_swig=no
|
||||
AC_ARG_ENABLE(swig-version-check, AS_HELP_STRING([--disable-swig-version-check],[Disable swig version check to build python modules with older swig even though that is unreliable]))
|
||||
if test "$enable_swig_version_check" = "yes"; then
|
||||
AC_PROG_SWIG(2.0.1)
|
||||
AX_PKG_SWIG(2.0.1)
|
||||
else
|
||||
AC_PROG_SWIG
|
||||
AX_PKG_SWIG
|
||||
fi
|
||||
AC_MSG_CHECKING(SWIG)
|
||||
if test ! -x "$SWIG"; then
|
||||
@@ -934,7 +944,7 @@ else
|
||||
AC_MSG_RESULT([no])
|
||||
fi
|
||||
AC_CHECK_HEADERS([openssl/conf.h openssl/engine.h openssl/bn.h openssl/dh.h openssl/dsa.h openssl/rsa.h openssl/core_names.h openssl/param_build.h],,, [AC_INCLUDES_DEFAULT])
|
||||
AC_CHECK_FUNCS([OPENSSL_config EVP_sha1 EVP_sha256 EVP_sha512 FIPS_mode EVP_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 SSL_CTX_set_tmp_ecdh])
|
||||
|
||||
# these check_funcs need -lssl
|
||||
BAKLIBS="$LIBS"
|
||||
@@ -1137,7 +1147,8 @@ int main(void) {
|
||||
return 6;
|
||||
return 0;
|
||||
}
|
||||
]])] , [eval "ac_cv_c_gost_works=yes"], [eval "ac_cv_c_gost_works=no"])
|
||||
]])] , [eval "ac_cv_c_gost_works=yes"], [eval "ac_cv_c_gost_works=no"],
|
||||
[eval "ac_cv_c_gost_works=maybe"])
|
||||
CFLAGS="$BAKCFLAGS"
|
||||
else
|
||||
eval "ac_cv_c_gost_works=maybe"
|
||||
@@ -1170,8 +1181,17 @@ case "$enable_ecdsa" in
|
||||
;;
|
||||
*)
|
||||
if test $USE_NSS = "no" -a $USE_NETTLE = "no"; then
|
||||
AC_CHECK_FUNC(ECDSA_sign, [], [AC_MSG_ERROR([OpenSSL does not support ECDSA: please upgrade or rerun with --disable-ecdsa])])
|
||||
AC_CHECK_FUNC(SHA384_Init, [], [AC_MSG_ERROR([OpenSSL does not support SHA384: please upgrade or rerun with --disable-ecdsa])])
|
||||
AC_CHECK_FUNC(EVP_PKEY_fromdata, [
|
||||
# with EVP_PKEY_fromdata, check if EC is not disabled
|
||||
AC_CHECK_DECL([OPENSSL_NO_EC], [AC_MSG_ERROR([OpenSSL does not support ECDSA: please upgrade or rerun with --disable-ecdsa])
|
||||
], [], [AC_INCLUDES_DEFAULT
|
||||
#include <openssl/evp.h>
|
||||
])
|
||||
], [
|
||||
# without EVP_PKEY_fromdata, older openssl, check for support
|
||||
AC_CHECK_FUNC(ECDSA_sign, [], [AC_MSG_ERROR([OpenSSL does not support ECDSA: please upgrade or rerun with --disable-ecdsa])])
|
||||
AC_CHECK_FUNC(SHA384_Init, [], [AC_MSG_ERROR([OpenSSL does not support SHA384: please upgrade or rerun with --disable-ecdsa])])
|
||||
])
|
||||
AC_CHECK_DECLS([NID_X9_62_prime256v1, NID_secp384r1], [], [AC_MSG_ERROR([OpenSSL does not support the ECDSA curves: please upgrade or rerun with --disable-ecdsa])], [AC_INCLUDES_DEFAULT
|
||||
#include <openssl/evp.h>
|
||||
])
|
||||
@@ -1522,13 +1542,17 @@ if test x_$enable_static_exe = x_yes; then
|
||||
if test "$on_mingw" = yes; then
|
||||
staticexe="-all-static"
|
||||
# for static compile, include gdi32 and zlib here.
|
||||
if echo $LIBS | grep 'lgdi32' >/dev/null; then
|
||||
if echo "$LIBS" | grep 'lgdi32' >/dev/null; then
|
||||
:
|
||||
else
|
||||
LIBS="$LIBS -lgdi32"
|
||||
fi
|
||||
AC_CHECK_LIB([z], [compress], [ LIBS="$LIBS -lz" ])
|
||||
LIBS="$LIBS -l:libssp.a"
|
||||
if echo "$LIBS" | grep -e "libssp.a" -e "lssp" >/dev/null; then
|
||||
:
|
||||
else
|
||||
LIBS="$LIBS -l:libssp.a"
|
||||
fi
|
||||
fi
|
||||
fi
|
||||
|
||||
@@ -1545,7 +1569,11 @@ if test x_$enable_fully_static = x_yes; then
|
||||
LIBS="$LIBS -lgdi32"
|
||||
fi
|
||||
AC_CHECK_LIB([z], [compress], [ LIBS="$LIBS -lz" ])
|
||||
LIBS="$LIBS -l:libssp.a"
|
||||
if echo "$LIBS" | grep -e "libssp.a" -e "lssp" >/dev/null; then
|
||||
:
|
||||
else
|
||||
LIBS="$LIBS -l:libssp.a"
|
||||
fi
|
||||
fi
|
||||
fi
|
||||
|
||||
@@ -1565,7 +1593,11 @@ if test "$USE_WINSOCK" = 1; then
|
||||
#include <windows.h>
|
||||
])
|
||||
AC_CHECK_TOOL(WINDRES, windres)
|
||||
LIBS="$LIBS -liphlpapi -lcrypt32"
|
||||
if echo "$LIBS" | grep crypt32 >/dev/null; then
|
||||
LIBS="$LIBS -liphlpapi"
|
||||
else
|
||||
LIBS="$LIBS -liphlpapi -lcrypt32"
|
||||
fi
|
||||
WINAPPS="unbound-service-install.exe unbound-service-remove.exe anchor-update.exe"
|
||||
AC_SUBST(WINAPPS)
|
||||
WIN_DAEMON_SRC="winrc/win_svc.c winrc/w_inst.c"
|
||||
@@ -1714,7 +1746,7 @@ int main(void) { return !(snprintf(NULL, 0, "test") == 4); }
|
||||
AC_MSG_RESULT(no)
|
||||
AC_DEFINE([SNPRINTF_RET_BROKEN], [], [define if (v)snprintf does not return length needed, (but length used)])
|
||||
AC_LIBOBJ(snprintf)
|
||||
])
|
||||
], [AC_MSG_RESULT(maybe)])
|
||||
fi
|
||||
fi
|
||||
AC_REPLACE_FUNCS(strlcat)
|
||||
@@ -1899,15 +1931,17 @@ case "$enable_ipset" in
|
||||
IPSET_OBJ="ipset.lo"
|
||||
AC_SUBST(IPSET_OBJ)
|
||||
|
||||
# mnl
|
||||
AC_ARG_WITH(libmnl, AS_HELP_STRING([--with-libmnl=path],[specify explicit path for libmnl.]),
|
||||
# BSD's pf
|
||||
AC_CHECK_HEADERS([net/pfvar.h], [], [
|
||||
# mnl
|
||||
AC_ARG_WITH(libmnl, AS_HELP_STRING([--with-libmnl=path],[specify explicit path for libmnl.]),
|
||||
[ ],[ withval="yes" ])
|
||||
found_libmnl="no"
|
||||
AC_MSG_CHECKING(for libmnl)
|
||||
if test x_$withval = x_ -o x_$withval = x_yes; then
|
||||
found_libmnl="no"
|
||||
AC_MSG_CHECKING(for libmnl)
|
||||
if test x_$withval = x_ -o x_$withval = x_yes; then
|
||||
withval="/usr/local /opt/local /usr/lib /usr/pkg /usr/sfw /usr"
|
||||
fi
|
||||
for dir in $withval ; do
|
||||
fi
|
||||
for dir in $withval ; do
|
||||
if test -f "$dir/include/libmnl/libmnl.h" -o -f "$dir/include/libmnl/libmnl/libmnl.h"; then
|
||||
found_libmnl="yes"
|
||||
dnl assume /usr is in default path.
|
||||
@@ -1925,10 +1959,14 @@ case "$enable_ipset" in
|
||||
LIBS="$LIBS -lmnl"
|
||||
break;
|
||||
fi
|
||||
done
|
||||
if test x_$found_libmnl != x_yes; then
|
||||
AC_MSG_ERROR([Could not find libmnl, libmnl.h])
|
||||
fi
|
||||
done
|
||||
if test x_$found_libmnl != x_yes; then
|
||||
AC_MSG_ERROR([Could not find libmnl, libmnl.h])
|
||||
fi
|
||||
], [
|
||||
#include <netinet/in.h>
|
||||
#include <net/if.h>
|
||||
])
|
||||
;;
|
||||
no|*)
|
||||
# nothing
|
||||
@@ -1944,7 +1982,7 @@ case "$enable_explicit_port_randomisation" in
|
||||
esac
|
||||
|
||||
if echo "$host" | $GREP -i -e linux >/dev/null; then
|
||||
AC_ARG_ENABLE(linux-ip-local-port-range, AC_HELP_STRING([--enable-linux-ip-local-port-range], [Define this to enable use of /proc/sys/net/ipv4/ip_local_port_range as a default outgoing port range. This is only for the libunbound on Linux and does not affect unbound resolving daemon itself. This may severely limit the number of available outgoing ports and thus decrease randomness. Define this only when the target system restricts (e.g. some of SELinux enabled distributions) the use of non-ephemeral ports.]))
|
||||
AC_ARG_ENABLE(linux-ip-local-port-range, AS_HELP_STRING([--enable-linux-ip-local-port-range], [Define this to enable use of /proc/sys/net/ipv4/ip_local_port_range as a default outgoing port range. This is only for the libunbound on Linux and does not affect unbound resolving daemon itself. This may severely limit the number of available outgoing ports and thus decrease randomness. Define this only when the target system restricts (e.g. some of SELinux enabled distributions) the use of non-ephemeral ports.]))
|
||||
case "$enable_linux_ip_local_port_range" in
|
||||
yes)
|
||||
AC_DEFINE([USE_LINUX_IP_LOCAL_PORT_RANGE], [1], [Define this to enable use of /proc/sys/net/ipv4/ip_local_port_range as a default outgoing port range. This is only for the libunbound on Linux and does not affect unbound resolving daemon itself. This may severely limit the number of available outgoing ports and thus decrease randomness. Define this only when the target system restricts (e.g. some of SELinux enabled distributions) the use of non-ephemeral ports.])
|
||||
|
||||
@@ -22,4 +22,13 @@ pidfile=${unbound_pidfile:-"/usr/local/etc/unbound/unbound.pid"}
|
||||
command_args=${unbound_flags:-"-c /usr/local/etc/unbound/unbound.conf"}
|
||||
extra_commands="reload"
|
||||
|
||||
if test "$1" = "stop" ; then
|
||||
run_rc_command "$1"
|
||||
ret=$?
|
||||
if test $ret -eq 0; then
|
||||
rm -f "$pidfile"
|
||||
fi
|
||||
exit $ret
|
||||
fi
|
||||
|
||||
run_rc_command "$1"
|
||||
|
||||
@@ -75,6 +75,7 @@ stop() {
|
||||
retval=$?
|
||||
echo
|
||||
[ $retval -eq 0 ] && rm -f $lockfile
|
||||
[ $retval -eq 0 ] && rm -f $pidfile
|
||||
if egrep -q '^/[^[:space:]]+[[:space:]]+'${rootdir}'/dev/log' /proc/mounts; then
|
||||
umount ${rootdir}/dev/log >/dev/null 2>&1
|
||||
fi;
|
||||
|
||||
@@ -58,6 +58,7 @@ stop() {
|
||||
killproc -p $pidfile unbound
|
||||
retval=$?
|
||||
[ $retval -eq 0 ] && rm -f $lockfile
|
||||
[ $retval -eq 0 ] && rm -f $pidfile
|
||||
for mountfile in /dev/log /dev/urandom /etc/localtime /etc/resolv.conf /var/run/unbound
|
||||
do
|
||||
if egrep -q '^/[^[:space:]]+[[:space:]]+'${rootdir}''${mountfile}'' /proc/mounts; then
|
||||
|
||||
@@ -75,6 +75,7 @@ stop() {
|
||||
retval=$?
|
||||
echo
|
||||
[ $retval -eq 0 ] && rm -f $lockfile
|
||||
[ $retval -eq 0 ] && rm -f $pidfile
|
||||
if egrep -q '^/[^[:space:]]+[[:space:]]+'${rootdir}'/dev/log' /proc/mounts; then
|
||||
umount ${rootdir}/dev/log >/dev/null 2>&1
|
||||
fi;
|
||||
|
||||
@@ -42,8 +42,8 @@
|
||||
[Unit]
|
||||
Description=Validating, recursive, and caching DNS resolver
|
||||
Documentation=man:unbound(8)
|
||||
After=network.target
|
||||
Before=network-online.target nss-lookup.target
|
||||
After=network-online.target
|
||||
Before=nss-lookup.target
|
||||
|
||||
[Install]
|
||||
WantedBy=multi-user.target
|
||||
|
||||
@@ -14,8 +14,8 @@
|
||||
[Unit]
|
||||
Description=Validating, recursive, and caching DNS resolver
|
||||
Documentation=man:unbound(8)
|
||||
After=network.target
|
||||
Before=network-online.target nss-lookup.target
|
||||
After=network-online.target
|
||||
Before=nss-lookup.target
|
||||
Wants=nss-lookup.target
|
||||
|
||||
[Install]
|
||||
|
||||
+16
-7
@@ -839,6 +839,7 @@ int print_deleg_lookup(RES* ssl, struct worker* worker, uint8_t* nm,
|
||||
char b[260];
|
||||
struct query_info qinfo;
|
||||
struct iter_hints_stub* stub;
|
||||
int nolock = 0;
|
||||
regional_free_all(region);
|
||||
qinfo.qname = nm;
|
||||
qinfo.qname_len = nmlen;
|
||||
@@ -850,13 +851,16 @@ int print_deleg_lookup(RES* ssl, struct worker* worker, uint8_t* nm,
|
||||
if(!ssl_printf(ssl, "The following name servers are used for lookup "
|
||||
"of %s\n", b))
|
||||
return 0;
|
||||
|
||||
dp = forwards_lookup(worker->env.fwds, nm, qinfo.qclass);
|
||||
|
||||
dp = forwards_lookup(worker->env.fwds, nm, qinfo.qclass, nolock);
|
||||
if(dp) {
|
||||
if(!ssl_printf(ssl, "forwarding request:\n"))
|
||||
if(!ssl_printf(ssl, "forwarding request:\n")) {
|
||||
lock_rw_unlock(&worker->env.fwds->lock);
|
||||
return 0;
|
||||
}
|
||||
print_dp_main(ssl, dp, NULL);
|
||||
print_dp_details(ssl, worker, dp);
|
||||
lock_rw_unlock(&worker->env.fwds->lock);
|
||||
return 1;
|
||||
}
|
||||
|
||||
@@ -892,21 +896,26 @@ int print_deleg_lookup(RES* ssl, struct worker* worker, uint8_t* nm,
|
||||
return 0;
|
||||
continue;
|
||||
}
|
||||
}
|
||||
}
|
||||
stub = hints_lookup_stub(worker->env.hints, nm, qinfo.qclass,
|
||||
dp);
|
||||
dp, nolock);
|
||||
if(stub) {
|
||||
if(stub->noprime) {
|
||||
if(!ssl_printf(ssl, "The noprime stub servers "
|
||||
"are used:\n"))
|
||||
"are used:\n")) {
|
||||
lock_rw_unlock(&worker->env.hints->lock);
|
||||
return 0;
|
||||
}
|
||||
} else {
|
||||
if(!ssl_printf(ssl, "The stub is primed "
|
||||
"with servers:\n"))
|
||||
"with servers:\n")) {
|
||||
lock_rw_unlock(&worker->env.hints->lock);
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
print_dp_main(ssl, stub->dp, NULL);
|
||||
print_dp_details(ssl, worker, stub->dp);
|
||||
lock_rw_unlock(&worker->env.hints->lock);
|
||||
} else {
|
||||
print_dp_main(ssl, dp, msg);
|
||||
print_dp_details(ssl, worker, dp);
|
||||
|
||||
+52
-12
@@ -91,6 +91,8 @@
|
||||
#include "util/net_help.h"
|
||||
#include "sldns/keyraw.h"
|
||||
#include "respip/respip.h"
|
||||
#include "iterator/iter_fwd.h"
|
||||
#include "iterator/iter_hints.h"
|
||||
#include <signal.h>
|
||||
|
||||
#ifdef HAVE_SYSTEMD
|
||||
@@ -99,6 +101,9 @@
|
||||
#ifdef HAVE_NETDB_H
|
||||
#include <netdb.h>
|
||||
#endif
|
||||
#ifdef USE_CACHEDB
|
||||
#include "cachedb/cachedb.h"
|
||||
#endif
|
||||
|
||||
/** How many quit requests happened. */
|
||||
static int sig_record_quit = 0;
|
||||
@@ -260,6 +265,7 @@ daemon_init(void)
|
||||
free(daemon);
|
||||
return NULL;
|
||||
}
|
||||
daemon->env->modstack = &daemon->mods;
|
||||
/* init edns_known_options */
|
||||
if(!edns_known_options_init(daemon->env)) {
|
||||
free(daemon->env);
|
||||
@@ -321,17 +327,15 @@ static int setup_acl_for_ports(struct acl_list* list,
|
||||
struct listen_port* port_list)
|
||||
{
|
||||
struct acl_addr* acl_node;
|
||||
struct addrinfo* addr;
|
||||
for(; port_list; port_list=port_list->next) {
|
||||
if(!port_list->socket) {
|
||||
/* This is mainly for testbound where port_list is
|
||||
* empty. */
|
||||
continue;
|
||||
}
|
||||
addr = port_list->socket->addr;
|
||||
if(!(acl_node = acl_interface_insert(list,
|
||||
(struct sockaddr_storage*)addr->ai_addr,
|
||||
(socklen_t)addr->ai_addrlen,
|
||||
(struct sockaddr_storage*)port_list->socket->addr,
|
||||
port_list->socket->addrlen,
|
||||
acl_refuse))) {
|
||||
return 0;
|
||||
}
|
||||
@@ -340,7 +344,7 @@ static int setup_acl_for_ports(struct acl_list* list,
|
||||
return 1;
|
||||
}
|
||||
|
||||
int
|
||||
int
|
||||
daemon_open_shared_ports(struct daemon* daemon)
|
||||
{
|
||||
log_assert(daemon);
|
||||
@@ -440,6 +444,19 @@ daemon_open_shared_ports(struct daemon* daemon)
|
||||
return 1;
|
||||
}
|
||||
|
||||
int
|
||||
daemon_privileged(struct daemon* daemon)
|
||||
{
|
||||
daemon->env->cfg = daemon->cfg;
|
||||
daemon->env->alloc = &daemon->superalloc;
|
||||
daemon->env->worker = NULL;
|
||||
if(!modstack_call_startup(&daemon->mods, daemon->cfg->module_conf,
|
||||
daemon->env)) {
|
||||
fatal_exit("failed to startup modules");
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
/**
|
||||
* Setup modules. setup module stack.
|
||||
* @param daemon: the daemon
|
||||
@@ -449,11 +466,15 @@ static void daemon_setup_modules(struct daemon* daemon)
|
||||
daemon->env->cfg = daemon->cfg;
|
||||
daemon->env->alloc = &daemon->superalloc;
|
||||
daemon->env->worker = NULL;
|
||||
daemon->env->need_to_validate = 0; /* set by module init below */
|
||||
if(!modstack_setup(&daemon->mods, daemon->cfg->module_conf,
|
||||
daemon->env)) {
|
||||
fatal_exit("failed to setup modules");
|
||||
if(daemon->mods_inited) {
|
||||
modstack_call_deinit(&daemon->mods, daemon->env);
|
||||
}
|
||||
daemon->env->need_to_validate = 0; /* set by module init below */
|
||||
if(!modstack_call_init(&daemon->mods, daemon->cfg->module_conf,
|
||||
daemon->env)) {
|
||||
fatal_exit("failed to init modules");
|
||||
}
|
||||
daemon->mods_inited = 1;
|
||||
log_edns_known_options(VERB_ALGO, daemon->env);
|
||||
}
|
||||
|
||||
@@ -499,7 +520,10 @@ daemon_clear_allocs(struct daemon* daemon)
|
||||
{
|
||||
int i;
|
||||
|
||||
for(i=0; i<daemon->num; i++) {
|
||||
/* daemon->num may be different during reloads (after configuration
|
||||
* read). Use old_num which has the correct value used to setup the
|
||||
* worker_allocs */
|
||||
for(i=0; i<daemon->old_num; i++) {
|
||||
alloc_clear(daemon->worker_allocs[i]);
|
||||
free(daemon->worker_allocs[i]);
|
||||
}
|
||||
@@ -716,6 +740,12 @@ daemon_fork(struct daemon* daemon)
|
||||
fatal_exit("Could not create local zones: out of memory");
|
||||
if(!local_zones_apply_cfg(daemon->local_zones, daemon->cfg))
|
||||
fatal_exit("Could not set up local zones");
|
||||
if(!(daemon->env->fwds = forwards_create()) ||
|
||||
!forwards_apply_cfg(daemon->env->fwds, daemon->cfg))
|
||||
fatal_exit("Could not set forward zones");
|
||||
if(!(daemon->env->hints = hints_create()) ||
|
||||
!hints_apply_cfg(daemon->env->hints, daemon->cfg))
|
||||
fatal_exit("Could not set root or stub hints");
|
||||
|
||||
/* process raw response-ip configuration data */
|
||||
if(!(daemon->respip_set = respip_set_create()))
|
||||
@@ -740,6 +770,10 @@ daemon_fork(struct daemon* daemon)
|
||||
if(!edns_strings_apply_cfg(daemon->env->edns_strings, daemon->cfg))
|
||||
fatal_exit("Could not set up EDNS strings");
|
||||
|
||||
#ifdef USE_CACHEDB
|
||||
daemon->env->cachedb_enabled = cachedb_is_enabled(&daemon->mods,
|
||||
daemon->env);
|
||||
#endif
|
||||
/* response-ip-xxx options don't work as expected without the respip
|
||||
* module. To avoid run-time operational surprise we reject such
|
||||
* configuration. */
|
||||
@@ -832,6 +866,10 @@ daemon_cleanup(struct daemon* daemon)
|
||||
slabhash_clear(daemon->env->msg_cache);
|
||||
}
|
||||
daemon->old_num = daemon->num; /* save the current num */
|
||||
forwards_delete(daemon->env->fwds);
|
||||
daemon->env->fwds = NULL;
|
||||
hints_delete(daemon->env->hints);
|
||||
daemon->env->hints = NULL;
|
||||
local_zones_delete(daemon->local_zones);
|
||||
daemon->local_zones = NULL;
|
||||
respip_set_delete(daemon->respip_set);
|
||||
@@ -840,7 +878,7 @@ daemon_cleanup(struct daemon* daemon)
|
||||
daemon->views = NULL;
|
||||
if(daemon->env->auth_zones)
|
||||
auth_zones_cleanup(daemon->env->auth_zones);
|
||||
/* key cache is cleared by module desetup during next daemon_fork() */
|
||||
/* key cache is cleared by module deinit during next daemon_fork() */
|
||||
daemon_remote_clear(daemon->rc);
|
||||
for(i=0; i<daemon->num; i++)
|
||||
worker_delete(daemon->workers[i]);
|
||||
@@ -870,7 +908,9 @@ daemon_delete(struct daemon* daemon)
|
||||
size_t i;
|
||||
if(!daemon)
|
||||
return;
|
||||
modstack_desetup(&daemon->mods, daemon->env);
|
||||
modstack_call_deinit(&daemon->mods, daemon->env);
|
||||
modstack_call_destartup(&daemon->mods, daemon->env);
|
||||
modstack_free(&daemon->mods);
|
||||
daemon_remote_delete(daemon->rc);
|
||||
for(i = 0; i < daemon->num_ports; i++)
|
||||
listening_ports_free(daemon->ports[i]);
|
||||
|
||||
@@ -115,6 +115,8 @@ struct daemon {
|
||||
struct module_env* env;
|
||||
/** stack of module callbacks */
|
||||
struct module_stack mods;
|
||||
/** The module stack has been inited */
|
||||
int mods_inited;
|
||||
/** access control, which client IPs are allowed to connect */
|
||||
struct acl_list* acl;
|
||||
/** access control, which interfaces are allowed to connect */
|
||||
@@ -162,6 +164,15 @@ struct daemon* daemon_init(void);
|
||||
*/
|
||||
int daemon_open_shared_ports(struct daemon* daemon);
|
||||
|
||||
/**
|
||||
* Do daemon setup that needs privileges
|
||||
* like opening privileged ports or opening device files.
|
||||
* The cfg member pointer must have been set for the daemon.
|
||||
* @param daemon: the daemon.
|
||||
* @return: false on error.
|
||||
*/
|
||||
int daemon_privileged(struct daemon* daemon);
|
||||
|
||||
/**
|
||||
* Fork workers and start service.
|
||||
* When the routine exits, it is no longer forked.
|
||||
|
||||
+357
-148
@@ -88,6 +88,9 @@
|
||||
#include "sldns/wire2str.h"
|
||||
#include "sldns/sbuffer.h"
|
||||
#include "util/timeval_func.h"
|
||||
#ifdef USE_CACHEDB
|
||||
#include "cachedb/cachedb.h"
|
||||
#endif
|
||||
|
||||
#ifdef HAVE_SYS_TYPES_H
|
||||
# include <sys/types.h>
|
||||
@@ -107,6 +110,10 @@
|
||||
/** what to put on statistics lines between var and value, ": " or "=" */
|
||||
#define SQ "="
|
||||
|
||||
/** Acceptable lengths of str lines */
|
||||
#define MAX_CMD_STRLINE 1024
|
||||
#define MAX_STDIN_STRLINE 2048
|
||||
|
||||
static int
|
||||
remote_setup_ctx(struct daemon_remote* rc, struct config_file* cfg)
|
||||
{
|
||||
@@ -523,12 +530,13 @@ ssl_print_text(RES* res, const char* text)
|
||||
if(res->ssl) {
|
||||
ERR_clear_error();
|
||||
if((r=SSL_write(res->ssl, text, (int)strlen(text))) <= 0) {
|
||||
if(SSL_get_error(res->ssl, r) == SSL_ERROR_ZERO_RETURN) {
|
||||
int r2;
|
||||
if((r2=SSL_get_error(res->ssl, r)) == SSL_ERROR_ZERO_RETURN) {
|
||||
verbose(VERB_QUERY, "warning, in SSL_write, peer "
|
||||
"closed connection");
|
||||
return 0;
|
||||
}
|
||||
log_crypto_err("could not SSL_write");
|
||||
log_crypto_err_io("could not SSL_write", r2);
|
||||
return 0;
|
||||
}
|
||||
} else {
|
||||
@@ -552,7 +560,7 @@ ssl_print_text(RES* res, const char* text)
|
||||
static int
|
||||
ssl_print_vmsg(RES* ssl, const char* format, va_list args)
|
||||
{
|
||||
char msg[1024];
|
||||
char msg[65535];
|
||||
vsnprintf(msg, sizeof(msg), format, args);
|
||||
return ssl_print_text(ssl, msg);
|
||||
}
|
||||
@@ -579,11 +587,12 @@ ssl_read_line(RES* res, char* buf, size_t max)
|
||||
if(res->ssl) {
|
||||
ERR_clear_error();
|
||||
if((r=SSL_read(res->ssl, buf+len, 1)) <= 0) {
|
||||
if(SSL_get_error(res->ssl, r) == SSL_ERROR_ZERO_RETURN) {
|
||||
int r2;
|
||||
if((r2=SSL_get_error(res->ssl, r)) == SSL_ERROR_ZERO_RETURN) {
|
||||
buf[len] = 0;
|
||||
return 1;
|
||||
}
|
||||
log_crypto_err("could not SSL_read");
|
||||
log_crypto_err_io("could not SSL_read", r2);
|
||||
return 0;
|
||||
}
|
||||
} else {
|
||||
@@ -596,7 +605,7 @@ ssl_read_line(RES* res, char* buf, size_t max)
|
||||
}
|
||||
if(errno == EINTR || errno == EAGAIN)
|
||||
continue;
|
||||
log_err("could not recv: %s",
|
||||
if(rr < 0) log_err("could not recv: %s",
|
||||
sock_strerror(errno));
|
||||
return 0;
|
||||
}
|
||||
@@ -631,6 +640,25 @@ static void send_ok(RES* ssl)
|
||||
(void)ssl_printf(ssl, "ok\n");
|
||||
}
|
||||
|
||||
/** tell other processes to execute the command */
|
||||
static void
|
||||
distribute_cmd(struct daemon_remote* rc, RES* ssl, char* cmd)
|
||||
{
|
||||
int i;
|
||||
if(!cmd || !ssl)
|
||||
return;
|
||||
/* skip i=0 which is me */
|
||||
for(i=1; i<rc->worker->daemon->num; i++) {
|
||||
worker_send_cmd(rc->worker->daemon->workers[i],
|
||||
worker_cmd_remote);
|
||||
if(!tube_write_msg(rc->worker->daemon->workers[i]->cmd,
|
||||
(uint8_t*)cmd, strlen(cmd)+1, 0)) {
|
||||
(void)ssl_printf(ssl, "error could not distribute cmd\n");
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/** do the stop command */
|
||||
static void
|
||||
do_stop(RES* ssl, struct worker* worker)
|
||||
@@ -1218,19 +1246,28 @@ do_zone_add(RES* ssl, struct local_zones* zones, char* arg)
|
||||
|
||||
/** Do the local_zones command */
|
||||
static void
|
||||
do_zones_add(RES* ssl, struct local_zones* zones)
|
||||
do_zones_add(struct daemon_remote* rc, RES* ssl, struct worker* worker)
|
||||
{
|
||||
char buf[2048];
|
||||
char buf[MAX_CMD_STRLINE + MAX_STDIN_STRLINE] = "local_zone ";
|
||||
int num = 0;
|
||||
while(ssl_read_line(ssl, buf, sizeof(buf))) {
|
||||
if(buf[0] == 0x04 && buf[1] == 0)
|
||||
break; /* end of transmission */
|
||||
if(!perform_zone_add(ssl, zones, buf)) {
|
||||
if(!ssl_printf(ssl, "error for input line: %s\n", buf))
|
||||
size_t cmd_len = strlen(buf);
|
||||
while(ssl_read_line(ssl, buf+cmd_len, MAX_STDIN_STRLINE)) {
|
||||
if(buf[0+cmd_len] == 0 ||
|
||||
(buf[0+cmd_len] == 0x04 && buf[1+cmd_len] == 0))
|
||||
break; /* zero byte line or end of transmission */
|
||||
#ifdef THREADS_DISABLED
|
||||
/* distribute single item command */
|
||||
if(rc) distribute_cmd(rc, ssl, buf);
|
||||
#else
|
||||
(void)rc; /* unused */
|
||||
#endif
|
||||
if(!perform_zone_add(ssl, worker->daemon->local_zones,
|
||||
buf+cmd_len)) {
|
||||
if(!ssl_printf(ssl, "error for input line: %s\n",
|
||||
buf+cmd_len))
|
||||
return;
|
||||
}
|
||||
else
|
||||
num++;
|
||||
else num++;
|
||||
}
|
||||
(void)ssl_printf(ssl, "added %d zones\n", num);
|
||||
}
|
||||
@@ -1267,19 +1304,28 @@ do_zone_remove(RES* ssl, struct local_zones* zones, char* arg)
|
||||
|
||||
/** Do the local_zones_remove command */
|
||||
static void
|
||||
do_zones_remove(RES* ssl, struct local_zones* zones)
|
||||
do_zones_remove(struct daemon_remote* rc, RES* ssl, struct worker* worker)
|
||||
{
|
||||
char buf[2048];
|
||||
char buf[MAX_CMD_STRLINE + MAX_STDIN_STRLINE] = "local_zone_remove ";
|
||||
int num = 0;
|
||||
while(ssl_read_line(ssl, buf, sizeof(buf))) {
|
||||
if(buf[0] == 0x04 && buf[1] == 0)
|
||||
break; /* end of transmission */
|
||||
if(!perform_zone_remove(ssl, zones, buf)) {
|
||||
if(!ssl_printf(ssl, "error for input line: %s\n", buf))
|
||||
size_t cmd_len = strlen(buf);
|
||||
while(ssl_read_line(ssl, buf+cmd_len, MAX_STDIN_STRLINE)) {
|
||||
if(buf[0+cmd_len] == 0 ||
|
||||
(buf[0+cmd_len] == 0x04 && buf[1+cmd_len] == 0))
|
||||
break; /* zero byte line or end of transmission */
|
||||
#ifdef THREADS_DISABLED
|
||||
/* distribute single item command */
|
||||
if(rc) distribute_cmd(rc, ssl, buf);
|
||||
#else
|
||||
(void)rc; /* unused */
|
||||
#endif
|
||||
if(!perform_zone_remove(ssl, worker->daemon->local_zones,
|
||||
buf+cmd_len)) {
|
||||
if(!ssl_printf(ssl, "error for input line: %s\n",
|
||||
buf+cmd_len))
|
||||
return;
|
||||
}
|
||||
else
|
||||
num++;
|
||||
else num++;
|
||||
}
|
||||
(void)ssl_printf(ssl, "removed %d zones\n", num);
|
||||
}
|
||||
@@ -1331,15 +1377,24 @@ do_data_add(RES* ssl, struct local_zones* zones, char* arg)
|
||||
|
||||
/** Do the local_datas command */
|
||||
static void
|
||||
do_datas_add(RES* ssl, struct local_zones* zones)
|
||||
do_datas_add(struct daemon_remote* rc, RES* ssl, struct worker* worker)
|
||||
{
|
||||
char buf[2048];
|
||||
char buf[MAX_CMD_STRLINE + MAX_STDIN_STRLINE] = "local_data ";
|
||||
int num = 0, line = 0;
|
||||
while(ssl_read_line(ssl, buf, sizeof(buf))) {
|
||||
if(buf[0] == 0x04 && buf[1] == 0)
|
||||
break; /* end of transmission */
|
||||
size_t cmd_len = strlen(buf);
|
||||
while(ssl_read_line(ssl, buf+cmd_len, MAX_STDIN_STRLINE)) {
|
||||
if(buf[0+cmd_len] == 0 ||
|
||||
(buf[0+cmd_len] == 0x04 && buf[1+cmd_len] == 0))
|
||||
break; /* zero byte line or end of transmission */
|
||||
#ifdef THREADS_DISABLED
|
||||
/* distribute single item command */
|
||||
if(rc) distribute_cmd(rc, ssl, buf);
|
||||
#else
|
||||
(void)rc; /* unused */
|
||||
#endif
|
||||
line++;
|
||||
if(perform_data_add(ssl, zones, buf, line))
|
||||
if(perform_data_add(ssl, worker->daemon->local_zones,
|
||||
buf+cmd_len, line))
|
||||
num++;
|
||||
}
|
||||
(void)ssl_printf(ssl, "added %d datas\n", num);
|
||||
@@ -1371,19 +1426,28 @@ do_data_remove(RES* ssl, struct local_zones* zones, char* arg)
|
||||
|
||||
/** Do the local_datas_remove command */
|
||||
static void
|
||||
do_datas_remove(RES* ssl, struct local_zones* zones)
|
||||
do_datas_remove(struct daemon_remote* rc, RES* ssl, struct worker* worker)
|
||||
{
|
||||
char buf[2048];
|
||||
char buf[MAX_CMD_STRLINE + MAX_STDIN_STRLINE] = "local_data_remove ";
|
||||
int num = 0;
|
||||
while(ssl_read_line(ssl, buf, sizeof(buf))) {
|
||||
if(buf[0] == 0x04 && buf[1] == 0)
|
||||
break; /* end of transmission */
|
||||
if(!perform_data_remove(ssl, zones, buf)) {
|
||||
if(!ssl_printf(ssl, "error for input line: %s\n", buf))
|
||||
size_t cmd_len = strlen(buf);
|
||||
while(ssl_read_line(ssl, buf+cmd_len, MAX_STDIN_STRLINE)) {
|
||||
if(buf[0+cmd_len] == 0 ||
|
||||
(buf[0+cmd_len] == 0x04 && buf[1+cmd_len] == 0))
|
||||
break; /* zero byte line or end of transmission */
|
||||
#ifdef THREADS_DISABLED
|
||||
/* distribute single item command */
|
||||
if(rc) distribute_cmd(rc, ssl, buf);
|
||||
#else
|
||||
(void)rc; /* unused */
|
||||
#endif
|
||||
if(!perform_data_remove(ssl, worker->daemon->local_zones,
|
||||
buf+cmd_len)) {
|
||||
if(!ssl_printf(ssl, "error for input line: %s\n",
|
||||
buf+cmd_len))
|
||||
return;
|
||||
}
|
||||
else
|
||||
num++;
|
||||
else num++;
|
||||
}
|
||||
(void)ssl_printf(ssl, "removed %d datas\n", num);
|
||||
}
|
||||
@@ -1471,9 +1535,13 @@ do_view_data_add(RES* ssl, struct worker* worker, char* arg)
|
||||
|
||||
/** Add new RR data from stdin to view */
|
||||
static void
|
||||
do_view_datas_add(RES* ssl, struct worker* worker, char* arg)
|
||||
do_view_datas_add(struct daemon_remote* rc, RES* ssl, struct worker* worker,
|
||||
char* arg)
|
||||
{
|
||||
struct view* v;
|
||||
char buf[MAX_CMD_STRLINE + MAX_STDIN_STRLINE] = "view_local_data ";
|
||||
size_t cmd_len;
|
||||
int num = 0, line = 0;
|
||||
v = views_find_view(worker->daemon->views,
|
||||
arg, 1 /* get write lock*/);
|
||||
if(!v) {
|
||||
@@ -1487,8 +1555,25 @@ do_view_datas_add(RES* ssl, struct worker* worker, char* arg)
|
||||
return;
|
||||
}
|
||||
}
|
||||
do_datas_add(ssl, v->local_zones);
|
||||
/* put the view name in the command buf */
|
||||
(void)snprintf(buf+strlen(buf), sizeof(buf)-strlen(buf), "%s ", arg);
|
||||
cmd_len = strlen(buf);
|
||||
while(ssl_read_line(ssl, buf+cmd_len, MAX_STDIN_STRLINE)) {
|
||||
if(buf[0+cmd_len] == 0 ||
|
||||
(buf[0+cmd_len] == 0x04 && buf[1+cmd_len] == 0))
|
||||
break; /* zero byte line or end of transmission */
|
||||
#ifdef THREADS_DISABLED
|
||||
/* distribute single item command */
|
||||
if(rc) distribute_cmd(rc, ssl, buf);
|
||||
#else
|
||||
(void)rc; /* unused */
|
||||
#endif
|
||||
line++;
|
||||
if(perform_data_add(ssl, v->local_zones, buf+cmd_len, line))
|
||||
num++;
|
||||
}
|
||||
lock_rw_unlock(&v->lock);
|
||||
(void)ssl_printf(ssl, "added %d datas\n", num);
|
||||
}
|
||||
|
||||
/** Remove RR data from view */
|
||||
@@ -1516,9 +1601,13 @@ do_view_data_remove(RES* ssl, struct worker* worker, char* arg)
|
||||
|
||||
/** Remove RR data from stdin from view */
|
||||
static void
|
||||
do_view_datas_remove(RES* ssl, struct worker* worker, char* arg)
|
||||
do_view_datas_remove(struct daemon_remote* rc, RES* ssl, struct worker* worker,
|
||||
char* arg)
|
||||
{
|
||||
struct view* v;
|
||||
char buf[MAX_CMD_STRLINE + MAX_STDIN_STRLINE] = "view_local_data_remove ";
|
||||
int num = 0;
|
||||
size_t cmd_len;
|
||||
v = views_find_view(worker->daemon->views,
|
||||
arg, 1 /* get write lock*/);
|
||||
if(!v) {
|
||||
@@ -1530,9 +1619,28 @@ do_view_datas_remove(RES* ssl, struct worker* worker, char* arg)
|
||||
ssl_printf(ssl, "removed 0 datas\n");
|
||||
return;
|
||||
}
|
||||
|
||||
do_datas_remove(ssl, v->local_zones);
|
||||
/* put the view name in the command buf */
|
||||
(void)snprintf(buf+strlen(buf), sizeof(buf)-strlen(buf), "%s ", arg);
|
||||
cmd_len = strlen(buf);
|
||||
while(ssl_read_line(ssl, buf+cmd_len, MAX_STDIN_STRLINE)) {
|
||||
if(buf[0+cmd_len] == 0 ||
|
||||
(buf[0+cmd_len] == 0x04 && buf[1+cmd_len] == 0))
|
||||
break; /* zero byte line or end of transmission */
|
||||
#ifdef THREADS_DISABLED
|
||||
/* distribute single item command */
|
||||
if(rc) distribute_cmd(rc, ssl, buf);
|
||||
#else
|
||||
(void)rc; /* unused */
|
||||
#endif
|
||||
if(!perform_data_remove(ssl, v->local_zones, buf+cmd_len)) {
|
||||
if(!ssl_printf(ssl, "error for input line: %s\n",
|
||||
buf+cmd_len))
|
||||
return;
|
||||
}
|
||||
else num++;
|
||||
}
|
||||
lock_rw_unlock(&v->lock);
|
||||
(void)ssl_printf(ssl, "removed %d datas\n", num);
|
||||
}
|
||||
|
||||
/** cache lookup of nameservers */
|
||||
@@ -1551,7 +1659,7 @@ do_lookup(RES* ssl, struct worker* worker, char* arg)
|
||||
/** flush something from rrset and msg caches */
|
||||
static void
|
||||
do_cache_remove(struct worker* worker, uint8_t* nm, size_t nmlen,
|
||||
uint16_t t, uint16_t c)
|
||||
uint16_t t, uint16_t c, int remcachedb)
|
||||
{
|
||||
hashvalue_type h;
|
||||
struct query_info k;
|
||||
@@ -1571,6 +1679,29 @@ do_cache_remove(struct worker* worker, uint8_t* nm, size_t nmlen,
|
||||
h = query_info_hash(&k, BIT_CD);
|
||||
slabhash_remove(worker->env.msg_cache, h, &k);
|
||||
}
|
||||
#ifdef USE_CACHEDB
|
||||
if(remcachedb && worker->env.cachedb_enabled)
|
||||
cachedb_msg_remove_qinfo(&worker->env, &k);
|
||||
#else
|
||||
(void)remcachedb;
|
||||
#endif
|
||||
}
|
||||
|
||||
/** parse '+c' option, modifies string to return remainder. */
|
||||
static int
|
||||
parse_remcachedb(RES* ssl, char** arg, int* pc)
|
||||
{
|
||||
*arg = skipwhite(*arg);
|
||||
if((*arg)[0] == '+' && (*arg)[1] == 'c') {
|
||||
char* arg2;
|
||||
*pc = 1;
|
||||
if(!find_arg2(ssl, *arg, &arg2))
|
||||
return 0;
|
||||
*arg = arg2;
|
||||
return 1;
|
||||
}
|
||||
/* The option was not found, no problem */
|
||||
return 1;
|
||||
}
|
||||
|
||||
/** flush a type */
|
||||
@@ -1582,15 +1713,20 @@ do_flush_type(RES* ssl, struct worker* worker, char* arg)
|
||||
size_t nmlen;
|
||||
char* arg2;
|
||||
uint16_t t;
|
||||
int pc = 0; /* '+c' option */
|
||||
if(!parse_remcachedb(ssl, &arg, &pc))
|
||||
return;
|
||||
if(!find_arg2(ssl, arg, &arg2))
|
||||
return;
|
||||
if(!parse_arg_name(ssl, arg, &nm, &nmlen, &nmlabs))
|
||||
return;
|
||||
t = sldns_get_rr_type_by_name(arg2);
|
||||
if(t == 0 && strcmp(arg2, "TYPE0") != 0) {
|
||||
(void)ssl_printf(ssl, "error parsing RRset type: '%s'\n", arg2);
|
||||
free(nm);
|
||||
return;
|
||||
}
|
||||
do_cache_remove(worker, nm, nmlen, t, LDNS_RR_CLASS_IN);
|
||||
do_cache_remove(worker, nm, nmlen, t, LDNS_RR_CLASS_IN, pc);
|
||||
|
||||
free(nm);
|
||||
send_ok(ssl);
|
||||
@@ -1628,6 +1764,8 @@ struct del_info {
|
||||
socklen_t addrlen;
|
||||
/** socket address for host deletion */
|
||||
struct sockaddr_storage addr;
|
||||
/** if cachedb information should be flushed too */
|
||||
int remcachedb;
|
||||
};
|
||||
|
||||
/** callback to delete hosts in infra cache */
|
||||
@@ -1679,6 +1817,7 @@ do_flush_infra(RES* ssl, struct worker* worker, char* arg)
|
||||
inf.num_msgs = 0;
|
||||
inf.num_keys = 0;
|
||||
inf.addrlen = len;
|
||||
inf.remcachedb = 0;
|
||||
memmove(&inf.addr, &addr, len);
|
||||
slabhash_traverse(worker->env.infra_cache->hosts, 1, &infra_del_host,
|
||||
&inf);
|
||||
@@ -1725,6 +1864,10 @@ zone_del_msg(struct lruhash_entry* e, void* arg)
|
||||
d->serve_expired_ttl = inf->expired;
|
||||
inf->num_msgs++;
|
||||
}
|
||||
#ifdef USE_CACHEDB
|
||||
if(inf->remcachedb && inf->worker->env.cachedb_enabled)
|
||||
cachedb_msg_remove_qinfo(&inf->worker->env, &k->key);
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1752,6 +1895,9 @@ do_flush_zone(RES* ssl, struct worker* worker, char* arg)
|
||||
int nmlabs;
|
||||
size_t nmlen;
|
||||
struct del_info inf;
|
||||
int pc = 0; /* '+c' option */
|
||||
if(!parse_remcachedb(ssl, &arg, &pc))
|
||||
return;
|
||||
if(!parse_arg_name(ssl, arg, &nm, &nmlen, &nmlabs))
|
||||
return;
|
||||
/* delete all RRs and key entries from zone */
|
||||
@@ -1765,6 +1911,7 @@ do_flush_zone(RES* ssl, struct worker* worker, char* arg)
|
||||
inf.num_rrsets = 0;
|
||||
inf.num_msgs = 0;
|
||||
inf.num_keys = 0;
|
||||
inf.remcachedb = pc;
|
||||
slabhash_traverse(&worker->env.rrset_cache->table, 1,
|
||||
&zone_del_rrset, &inf);
|
||||
|
||||
@@ -1806,6 +1953,11 @@ bogus_del_msg(struct lruhash_entry* e, void* arg)
|
||||
if(d->security == sec_status_bogus) {
|
||||
d->ttl = inf->expired;
|
||||
inf->num_msgs++;
|
||||
#ifdef USE_CACHEDB
|
||||
if(inf->remcachedb && inf->worker->env.cachedb_enabled)
|
||||
cachedb_msg_remove_qinfo(&inf->worker->env,
|
||||
&((struct msgreply_entry*)e->key)->key);
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1824,9 +1976,12 @@ bogus_del_kcache(struct lruhash_entry* e, void* arg)
|
||||
|
||||
/** remove all bogus rrsets, msgs and keys from cache */
|
||||
static void
|
||||
do_flush_bogus(RES* ssl, struct worker* worker)
|
||||
do_flush_bogus(RES* ssl, struct worker* worker, char* arg)
|
||||
{
|
||||
struct del_info inf;
|
||||
int pc = 0; /* '+c' option */
|
||||
if(!parse_remcachedb(ssl, &arg, &pc))
|
||||
return;
|
||||
/* what we do is to set them all expired */
|
||||
inf.worker = worker;
|
||||
inf.expired = *worker->env.now;
|
||||
@@ -1834,6 +1989,7 @@ do_flush_bogus(RES* ssl, struct worker* worker)
|
||||
inf.num_rrsets = 0;
|
||||
inf.num_msgs = 0;
|
||||
inf.num_keys = 0;
|
||||
inf.remcachedb = pc;
|
||||
slabhash_traverse(&worker->env.rrset_cache->table, 1,
|
||||
&bogus_del_rrset, &inf);
|
||||
|
||||
@@ -1879,6 +2035,11 @@ negative_del_msg(struct lruhash_entry* e, void* arg)
|
||||
if(FLAGS_GET_RCODE(d->flags) != 0 || d->an_numrrsets == 0) {
|
||||
d->ttl = inf->expired;
|
||||
inf->num_msgs++;
|
||||
#ifdef USE_CACHEDB
|
||||
if(inf->remcachedb && inf->worker->env.cachedb_enabled)
|
||||
cachedb_msg_remove_qinfo(&inf->worker->env,
|
||||
&((struct msgreply_entry*)e->key)->key);
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1899,9 +2060,12 @@ negative_del_kcache(struct lruhash_entry* e, void* arg)
|
||||
|
||||
/** remove all negative(NODATA,NXDOMAIN), and servfail messages from cache */
|
||||
static void
|
||||
do_flush_negative(RES* ssl, struct worker* worker)
|
||||
do_flush_negative(RES* ssl, struct worker* worker, char* arg)
|
||||
{
|
||||
struct del_info inf;
|
||||
int pc = 0; /* '+c' option */
|
||||
if(!parse_remcachedb(ssl, &arg, &pc))
|
||||
return;
|
||||
/* what we do is to set them all expired */
|
||||
inf.worker = worker;
|
||||
inf.expired = *worker->env.now;
|
||||
@@ -1909,6 +2073,7 @@ do_flush_negative(RES* ssl, struct worker* worker)
|
||||
inf.num_rrsets = 0;
|
||||
inf.num_msgs = 0;
|
||||
inf.num_keys = 0;
|
||||
inf.remcachedb = pc;
|
||||
slabhash_traverse(&worker->env.rrset_cache->table, 1,
|
||||
&negative_del_rrset, &inf);
|
||||
|
||||
@@ -1932,20 +2097,23 @@ do_flush_name(RES* ssl, struct worker* w, char* arg)
|
||||
uint8_t* nm;
|
||||
int nmlabs;
|
||||
size_t nmlen;
|
||||
int pc = 0; /* '+c' option */
|
||||
if(!parse_remcachedb(ssl, &arg, &pc))
|
||||
return;
|
||||
if(!parse_arg_name(ssl, arg, &nm, &nmlen, &nmlabs))
|
||||
return;
|
||||
do_cache_remove(w, nm, nmlen, LDNS_RR_TYPE_A, LDNS_RR_CLASS_IN);
|
||||
do_cache_remove(w, nm, nmlen, LDNS_RR_TYPE_AAAA, LDNS_RR_CLASS_IN);
|
||||
do_cache_remove(w, nm, nmlen, LDNS_RR_TYPE_NS, LDNS_RR_CLASS_IN);
|
||||
do_cache_remove(w, nm, nmlen, LDNS_RR_TYPE_SOA, LDNS_RR_CLASS_IN);
|
||||
do_cache_remove(w, nm, nmlen, LDNS_RR_TYPE_CNAME, LDNS_RR_CLASS_IN);
|
||||
do_cache_remove(w, nm, nmlen, LDNS_RR_TYPE_DNAME, LDNS_RR_CLASS_IN);
|
||||
do_cache_remove(w, nm, nmlen, LDNS_RR_TYPE_MX, LDNS_RR_CLASS_IN);
|
||||
do_cache_remove(w, nm, nmlen, LDNS_RR_TYPE_PTR, LDNS_RR_CLASS_IN);
|
||||
do_cache_remove(w, nm, nmlen, LDNS_RR_TYPE_SRV, LDNS_RR_CLASS_IN);
|
||||
do_cache_remove(w, nm, nmlen, LDNS_RR_TYPE_NAPTR, LDNS_RR_CLASS_IN);
|
||||
do_cache_remove(w, nm, nmlen, LDNS_RR_TYPE_SVCB, LDNS_RR_CLASS_IN);
|
||||
do_cache_remove(w, nm, nmlen, LDNS_RR_TYPE_HTTPS, LDNS_RR_CLASS_IN);
|
||||
do_cache_remove(w, nm, nmlen, LDNS_RR_TYPE_A, LDNS_RR_CLASS_IN, pc);
|
||||
do_cache_remove(w, nm, nmlen, LDNS_RR_TYPE_AAAA, LDNS_RR_CLASS_IN, pc);
|
||||
do_cache_remove(w, nm, nmlen, LDNS_RR_TYPE_NS, LDNS_RR_CLASS_IN, pc);
|
||||
do_cache_remove(w, nm, nmlen, LDNS_RR_TYPE_SOA, LDNS_RR_CLASS_IN, pc);
|
||||
do_cache_remove(w, nm, nmlen, LDNS_RR_TYPE_CNAME, LDNS_RR_CLASS_IN, pc);
|
||||
do_cache_remove(w, nm, nmlen, LDNS_RR_TYPE_DNAME, LDNS_RR_CLASS_IN, pc);
|
||||
do_cache_remove(w, nm, nmlen, LDNS_RR_TYPE_MX, LDNS_RR_CLASS_IN, pc);
|
||||
do_cache_remove(w, nm, nmlen, LDNS_RR_TYPE_PTR, LDNS_RR_CLASS_IN, pc);
|
||||
do_cache_remove(w, nm, nmlen, LDNS_RR_TYPE_SRV, LDNS_RR_CLASS_IN, pc);
|
||||
do_cache_remove(w, nm, nmlen, LDNS_RR_TYPE_NAPTR, LDNS_RR_CLASS_IN, pc);
|
||||
do_cache_remove(w, nm, nmlen, LDNS_RR_TYPE_SVCB, LDNS_RR_CLASS_IN, pc);
|
||||
do_cache_remove(w, nm, nmlen, LDNS_RR_TYPE_HTTPS, LDNS_RR_CLASS_IN, pc);
|
||||
|
||||
free(nm);
|
||||
send_ok(ssl);
|
||||
@@ -1990,12 +2158,19 @@ static int
|
||||
print_root_fwds(RES* ssl, struct iter_forwards* fwds, uint8_t* root)
|
||||
{
|
||||
struct delegpt* dp;
|
||||
dp = forwards_lookup(fwds, root, LDNS_RR_CLASS_IN);
|
||||
if(!dp)
|
||||
int nolock = 0;
|
||||
dp = forwards_lookup(fwds, root, LDNS_RR_CLASS_IN, nolock);
|
||||
if(!dp) {
|
||||
return ssl_printf(ssl, "off (using root hints)\n");
|
||||
}
|
||||
/* if dp is returned it must be the root */
|
||||
log_assert(query_dname_compare(dp->name, root)==0);
|
||||
return ssl_print_name_dp(ssl, NULL, root, LDNS_RR_CLASS_IN, dp);
|
||||
if(!ssl_print_name_dp(ssl, NULL, root, LDNS_RR_CLASS_IN, dp)) {
|
||||
lock_rw_unlock(&fwds->lock);
|
||||
return 0;
|
||||
}
|
||||
lock_rw_unlock(&fwds->lock);
|
||||
return 1;
|
||||
}
|
||||
|
||||
/** parse args into delegpt */
|
||||
@@ -2061,12 +2236,13 @@ parse_delegpt(RES* ssl, char* args, uint8_t* nm)
|
||||
return dp;
|
||||
}
|
||||
|
||||
/** do the status command */
|
||||
/** do the forward command */
|
||||
static void
|
||||
do_forward(RES* ssl, struct worker* worker, char* args)
|
||||
{
|
||||
struct iter_forwards* fwd = worker->env.fwds;
|
||||
uint8_t* root = (uint8_t*)"\000";
|
||||
int nolock = 0;
|
||||
if(!fwd) {
|
||||
(void)ssl_printf(ssl, "error: structure not allocated\n");
|
||||
return;
|
||||
@@ -2080,12 +2256,12 @@ do_forward(RES* ssl, struct worker* worker, char* args)
|
||||
/* delete all the existing queries first */
|
||||
mesh_delete_all(worker->env.mesh);
|
||||
if(strcmp(args, "off") == 0) {
|
||||
forwards_delete_zone(fwd, LDNS_RR_CLASS_IN, root);
|
||||
forwards_delete_zone(fwd, LDNS_RR_CLASS_IN, root, nolock);
|
||||
} else {
|
||||
struct delegpt* dp;
|
||||
if(!(dp = parse_delegpt(ssl, args, root)))
|
||||
return;
|
||||
if(!forwards_add_zone(fwd, LDNS_RR_CLASS_IN, dp)) {
|
||||
if(!forwards_add_zone(fwd, LDNS_RR_CLASS_IN, dp, nolock)) {
|
||||
(void)ssl_printf(ssl, "error out of memory\n");
|
||||
return;
|
||||
}
|
||||
@@ -2095,7 +2271,7 @@ do_forward(RES* ssl, struct worker* worker, char* args)
|
||||
|
||||
static int
|
||||
parse_fs_args(RES* ssl, char* args, uint8_t** nm, struct delegpt** dp,
|
||||
int* insecure, int* prime)
|
||||
int* insecure, int* prime, int* tls)
|
||||
{
|
||||
char* zonename;
|
||||
char* rest;
|
||||
@@ -2110,6 +2286,8 @@ parse_fs_args(RES* ssl, char* args, uint8_t** nm, struct delegpt** dp,
|
||||
*insecure = 1;
|
||||
else if(*args == 'p' && prime)
|
||||
*prime = 1;
|
||||
else if(*args == 't' && tls)
|
||||
*tls = 1;
|
||||
else {
|
||||
(void)ssl_printf(ssl, "error: unknown option %s\n", args);
|
||||
return 0;
|
||||
@@ -2142,25 +2320,33 @@ static void
|
||||
do_forward_add(RES* ssl, struct worker* worker, char* args)
|
||||
{
|
||||
struct iter_forwards* fwd = worker->env.fwds;
|
||||
int insecure = 0;
|
||||
int insecure = 0, tls = 0;
|
||||
uint8_t* nm = NULL;
|
||||
struct delegpt* dp = NULL;
|
||||
if(!parse_fs_args(ssl, args, &nm, &dp, &insecure, NULL))
|
||||
int nolock = 1;
|
||||
if(!parse_fs_args(ssl, args, &nm, &dp, &insecure, NULL, &tls))
|
||||
return;
|
||||
if(tls)
|
||||
dp->ssl_upstream = 1;
|
||||
/* prelock forwarders for atomic operation with anchors */
|
||||
lock_rw_wrlock(&fwd->lock);
|
||||
if(insecure && worker->env.anchors) {
|
||||
if(!anchors_add_insecure(worker->env.anchors, LDNS_RR_CLASS_IN,
|
||||
nm)) {
|
||||
lock_rw_unlock(&fwd->lock);
|
||||
(void)ssl_printf(ssl, "error out of memory\n");
|
||||
delegpt_free_mlc(dp);
|
||||
free(nm);
|
||||
return;
|
||||
}
|
||||
}
|
||||
if(!forwards_add_zone(fwd, LDNS_RR_CLASS_IN, dp)) {
|
||||
if(!forwards_add_zone(fwd, LDNS_RR_CLASS_IN, dp, nolock)) {
|
||||
lock_rw_unlock(&fwd->lock);
|
||||
(void)ssl_printf(ssl, "error out of memory\n");
|
||||
free(nm);
|
||||
return;
|
||||
}
|
||||
lock_rw_unlock(&fwd->lock);
|
||||
free(nm);
|
||||
send_ok(ssl);
|
||||
}
|
||||
@@ -2172,12 +2358,16 @@ do_forward_remove(RES* ssl, struct worker* worker, char* args)
|
||||
struct iter_forwards* fwd = worker->env.fwds;
|
||||
int insecure = 0;
|
||||
uint8_t* nm = NULL;
|
||||
if(!parse_fs_args(ssl, args, &nm, NULL, &insecure, NULL))
|
||||
int nolock = 1;
|
||||
if(!parse_fs_args(ssl, args, &nm, NULL, &insecure, NULL, NULL))
|
||||
return;
|
||||
/* prelock forwarders for atomic operation with anchors */
|
||||
lock_rw_wrlock(&fwd->lock);
|
||||
if(insecure && worker->env.anchors)
|
||||
anchors_delete_insecure(worker->env.anchors, LDNS_RR_CLASS_IN,
|
||||
nm);
|
||||
forwards_delete_zone(fwd, LDNS_RR_CLASS_IN, nm);
|
||||
forwards_delete_zone(fwd, LDNS_RR_CLASS_IN, nm, nolock);
|
||||
lock_rw_unlock(&fwd->lock);
|
||||
free(nm);
|
||||
send_ok(ssl);
|
||||
}
|
||||
@@ -2187,38 +2377,53 @@ static void
|
||||
do_stub_add(RES* ssl, struct worker* worker, char* args)
|
||||
{
|
||||
struct iter_forwards* fwd = worker->env.fwds;
|
||||
int insecure = 0, prime = 0;
|
||||
int insecure = 0, prime = 0, tls = 0;
|
||||
uint8_t* nm = NULL;
|
||||
struct delegpt* dp = NULL;
|
||||
if(!parse_fs_args(ssl, args, &nm, &dp, &insecure, &prime))
|
||||
int nolock = 1;
|
||||
if(!parse_fs_args(ssl, args, &nm, &dp, &insecure, &prime, &tls))
|
||||
return;
|
||||
if(tls)
|
||||
dp->ssl_upstream = 1;
|
||||
/* prelock forwarders and hints for atomic operation with anchors */
|
||||
lock_rw_wrlock(&fwd->lock);
|
||||
lock_rw_wrlock(&worker->env.hints->lock);
|
||||
if(insecure && worker->env.anchors) {
|
||||
if(!anchors_add_insecure(worker->env.anchors, LDNS_RR_CLASS_IN,
|
||||
nm)) {
|
||||
lock_rw_unlock(&fwd->lock);
|
||||
lock_rw_unlock(&worker->env.hints->lock);
|
||||
(void)ssl_printf(ssl, "error out of memory\n");
|
||||
delegpt_free_mlc(dp);
|
||||
free(nm);
|
||||
return;
|
||||
}
|
||||
}
|
||||
if(!forwards_add_stub_hole(fwd, LDNS_RR_CLASS_IN, nm)) {
|
||||
if(!forwards_add_stub_hole(fwd, LDNS_RR_CLASS_IN, nm, nolock)) {
|
||||
if(insecure && worker->env.anchors)
|
||||
anchors_delete_insecure(worker->env.anchors,
|
||||
LDNS_RR_CLASS_IN, nm);
|
||||
lock_rw_unlock(&fwd->lock);
|
||||
lock_rw_unlock(&worker->env.hints->lock);
|
||||
(void)ssl_printf(ssl, "error out of memory\n");
|
||||
delegpt_free_mlc(dp);
|
||||
free(nm);
|
||||
return;
|
||||
}
|
||||
if(!hints_add_stub(worker->env.hints, LDNS_RR_CLASS_IN, dp, !prime)) {
|
||||
if(!hints_add_stub(worker->env.hints, LDNS_RR_CLASS_IN, dp, !prime,
|
||||
nolock)) {
|
||||
(void)ssl_printf(ssl, "error out of memory\n");
|
||||
forwards_delete_stub_hole(fwd, LDNS_RR_CLASS_IN, nm);
|
||||
forwards_delete_stub_hole(fwd, LDNS_RR_CLASS_IN, nm, nolock);
|
||||
if(insecure && worker->env.anchors)
|
||||
anchors_delete_insecure(worker->env.anchors,
|
||||
LDNS_RR_CLASS_IN, nm);
|
||||
lock_rw_unlock(&fwd->lock);
|
||||
lock_rw_unlock(&worker->env.hints->lock);
|
||||
free(nm);
|
||||
return;
|
||||
}
|
||||
lock_rw_unlock(&fwd->lock);
|
||||
lock_rw_unlock(&worker->env.hints->lock);
|
||||
free(nm);
|
||||
send_ok(ssl);
|
||||
}
|
||||
@@ -2230,13 +2435,19 @@ do_stub_remove(RES* ssl, struct worker* worker, char* args)
|
||||
struct iter_forwards* fwd = worker->env.fwds;
|
||||
int insecure = 0;
|
||||
uint8_t* nm = NULL;
|
||||
if(!parse_fs_args(ssl, args, &nm, NULL, &insecure, NULL))
|
||||
int nolock = 1;
|
||||
if(!parse_fs_args(ssl, args, &nm, NULL, &insecure, NULL, NULL))
|
||||
return;
|
||||
/* prelock forwarders and hints for atomic operation with anchors */
|
||||
lock_rw_wrlock(&fwd->lock);
|
||||
lock_rw_wrlock(&worker->env.hints->lock);
|
||||
if(insecure && worker->env.anchors)
|
||||
anchors_delete_insecure(worker->env.anchors, LDNS_RR_CLASS_IN,
|
||||
nm);
|
||||
forwards_delete_stub_hole(fwd, LDNS_RR_CLASS_IN, nm);
|
||||
hints_delete_stub(worker->env.hints, LDNS_RR_CLASS_IN, nm);
|
||||
forwards_delete_stub_hole(fwd, LDNS_RR_CLASS_IN, nm, nolock);
|
||||
hints_delete_stub(worker->env.hints, LDNS_RR_CLASS_IN, nm, nolock);
|
||||
lock_rw_unlock(&fwd->lock);
|
||||
lock_rw_unlock(&worker->env.hints->lock);
|
||||
free(nm);
|
||||
send_ok(ssl);
|
||||
}
|
||||
@@ -2665,6 +2876,7 @@ do_list_forwards(RES* ssl, struct worker* worker)
|
||||
struct iter_forward_zone* z;
|
||||
struct trust_anchor* a;
|
||||
int insecure;
|
||||
lock_rw_rdlock(&fwds->lock);
|
||||
RBTREE_FOR(z, struct iter_forward_zone*, fwds->tree) {
|
||||
if(!z->dp) continue; /* skip empty marker for stub */
|
||||
|
||||
@@ -2679,9 +2891,12 @@ do_list_forwards(RES* ssl, struct worker* worker)
|
||||
}
|
||||
|
||||
if(!ssl_print_name_dp(ssl, (insecure?"forward +i":"forward"),
|
||||
z->name, z->dclass, z->dp))
|
||||
z->name, z->dclass, z->dp)) {
|
||||
lock_rw_unlock(&fwds->lock);
|
||||
return;
|
||||
}
|
||||
}
|
||||
lock_rw_unlock(&fwds->lock);
|
||||
}
|
||||
|
||||
/** do the list_stubs command */
|
||||
@@ -2692,6 +2907,7 @@ do_list_stubs(RES* ssl, struct worker* worker)
|
||||
struct trust_anchor* a;
|
||||
int insecure;
|
||||
char str[32];
|
||||
lock_rw_rdlock(&worker->env.hints->lock);
|
||||
RBTREE_FOR(z, struct iter_hints_stub*, &worker->env.hints->tree) {
|
||||
|
||||
/* see if it is insecure */
|
||||
@@ -2707,9 +2923,12 @@ do_list_stubs(RES* ssl, struct worker* worker)
|
||||
snprintf(str, sizeof(str), "stub %sprime%s",
|
||||
(z->noprime?"no":""), (insecure?" +i":""));
|
||||
if(!ssl_print_name_dp(ssl, str, z->node.name,
|
||||
z->node.dclass, z->dp))
|
||||
z->node.dclass, z->dp)) {
|
||||
lock_rw_unlock(&worker->env.hints->lock);
|
||||
return;
|
||||
}
|
||||
}
|
||||
lock_rw_unlock(&worker->env.hints->lock);
|
||||
}
|
||||
|
||||
/** do the list_auth_zones command */
|
||||
@@ -2976,25 +3195,6 @@ do_rpz_disable(RES* ssl, struct worker* worker, char* arg)
|
||||
do_rpz_enable_disable(ssl, worker, arg, 0);
|
||||
}
|
||||
|
||||
/** tell other processes to execute the command */
|
||||
static void
|
||||
distribute_cmd(struct daemon_remote* rc, RES* ssl, char* cmd)
|
||||
{
|
||||
int i;
|
||||
if(!cmd || !ssl)
|
||||
return;
|
||||
/* skip i=0 which is me */
|
||||
for(i=1; i<rc->worker->daemon->num; i++) {
|
||||
worker_send_cmd(rc->worker->daemon->workers[i],
|
||||
worker_cmd_remote);
|
||||
if(!tube_write_msg(rc->worker->daemon->workers[i]->cmd,
|
||||
(uint8_t*)cmd, strlen(cmd)+1, 0)) {
|
||||
ssl_printf(ssl, "error could not distribute cmd\n");
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/** check for name with end-of-string, space or tab after it */
|
||||
static int
|
||||
cmdcmp(char* p, const char* cmd, size_t len)
|
||||
@@ -3028,9 +3228,23 @@ execute_cmd(struct daemon_remote* rc, RES* ssl, char* cmd,
|
||||
do_status(ssl, worker);
|
||||
return;
|
||||
} else if(cmdcmp(p, "dump_cache", 10)) {
|
||||
#ifdef THREADS_DISABLED
|
||||
if(worker->daemon->num > 1) {
|
||||
(void)ssl_printf(ssl, "dump_cache/load_cache is not "
|
||||
"supported in multi-process operation\n");
|
||||
return;
|
||||
}
|
||||
#endif
|
||||
(void)dump_cache(ssl, worker);
|
||||
return;
|
||||
} else if(cmdcmp(p, "load_cache", 10)) {
|
||||
#ifdef THREADS_DISABLED
|
||||
if(worker->daemon->num > 1) {
|
||||
/* The warning can't be printed when stdin is sending
|
||||
* data; just return */
|
||||
return;
|
||||
}
|
||||
#endif
|
||||
if(load_cache(ssl, worker)) send_ok(ssl);
|
||||
return;
|
||||
} else if(cmdcmp(p, "list_forwards", 13)) {
|
||||
@@ -3069,26 +3283,6 @@ execute_cmd(struct daemon_remote* rc, RES* ssl, char* cmd,
|
||||
} else if(cmdcmp(p, "auth_zone_transfer", 18)) {
|
||||
do_auth_zone_transfer(ssl, worker, skipwhite(p+18));
|
||||
return;
|
||||
} else if(cmdcmp(p, "stub_add", 8)) {
|
||||
/* must always distribute this cmd */
|
||||
if(rc) distribute_cmd(rc, ssl, cmd);
|
||||
do_stub_add(ssl, worker, skipwhite(p+8));
|
||||
return;
|
||||
} else if(cmdcmp(p, "stub_remove", 11)) {
|
||||
/* must always distribute this cmd */
|
||||
if(rc) distribute_cmd(rc, ssl, cmd);
|
||||
do_stub_remove(ssl, worker, skipwhite(p+11));
|
||||
return;
|
||||
} else if(cmdcmp(p, "forward_add", 11)) {
|
||||
/* must always distribute this cmd */
|
||||
if(rc) distribute_cmd(rc, ssl, cmd);
|
||||
do_forward_add(ssl, worker, skipwhite(p+11));
|
||||
return;
|
||||
} else if(cmdcmp(p, "forward_remove", 14)) {
|
||||
/* must always distribute this cmd */
|
||||
if(rc) distribute_cmd(rc, ssl, cmd);
|
||||
do_forward_remove(ssl, worker, skipwhite(p+14));
|
||||
return;
|
||||
} else if(cmdcmp(p, "insecure_add", 12)) {
|
||||
/* must always distribute this cmd */
|
||||
if(rc) distribute_cmd(rc, ssl, cmd);
|
||||
@@ -3099,11 +3293,6 @@ execute_cmd(struct daemon_remote* rc, RES* ssl, char* cmd,
|
||||
if(rc) distribute_cmd(rc, ssl, cmd);
|
||||
do_insecure_remove(ssl, worker, skipwhite(p+15));
|
||||
return;
|
||||
} else if(cmdcmp(p, "forward", 7)) {
|
||||
/* must always distribute this cmd */
|
||||
if(rc) distribute_cmd(rc, ssl, cmd);
|
||||
do_forward(ssl, worker, skipwhite(p+7));
|
||||
return;
|
||||
} else if(cmdcmp(p, "flush_stats", 11)) {
|
||||
/* must always distribute this cmd */
|
||||
if(rc) distribute_cmd(rc, ssl, cmd);
|
||||
@@ -3117,6 +3306,27 @@ execute_cmd(struct daemon_remote* rc, RES* ssl, char* cmd,
|
||||
} else if(cmdcmp(p, "lookup", 6)) {
|
||||
do_lookup(ssl, worker, skipwhite(p+6));
|
||||
return;
|
||||
/* The following are commands that read stdin.
|
||||
* Each line needs to be distributed if THREADS_DISABLED.
|
||||
*/
|
||||
} else if(cmdcmp(p, "local_zones_remove", 18)) {
|
||||
do_zones_remove(rc, ssl, worker);
|
||||
return;
|
||||
} else if(cmdcmp(p, "local_zones", 11)) {
|
||||
do_zones_add(rc, ssl, worker);
|
||||
return;
|
||||
} else if(cmdcmp(p, "local_datas_remove", 18)) {
|
||||
do_datas_remove(rc, ssl, worker);
|
||||
return;
|
||||
} else if(cmdcmp(p, "local_datas", 11)) {
|
||||
do_datas_add(rc, ssl, worker);
|
||||
return;
|
||||
} else if(cmdcmp(p, "view_local_datas_remove", 23)){
|
||||
do_view_datas_remove(rc, ssl, worker, skipwhite(p+23));
|
||||
return;
|
||||
} else if(cmdcmp(p, "view_local_datas", 16)) {
|
||||
do_view_datas_add(rc, ssl, worker, skipwhite(p+16));
|
||||
return;
|
||||
}
|
||||
|
||||
#ifdef THREADS_DISABLED
|
||||
@@ -3131,32 +3341,30 @@ execute_cmd(struct daemon_remote* rc, RES* ssl, char* cmd,
|
||||
do_verbosity(ssl, skipwhite(p+9));
|
||||
} else if(cmdcmp(p, "local_zone_remove", 17)) {
|
||||
do_zone_remove(ssl, worker->daemon->local_zones, skipwhite(p+17));
|
||||
} else if(cmdcmp(p, "local_zones_remove", 18)) {
|
||||
do_zones_remove(ssl, worker->daemon->local_zones);
|
||||
} else if(cmdcmp(p, "local_zone", 10)) {
|
||||
do_zone_add(ssl, worker->daemon->local_zones, skipwhite(p+10));
|
||||
} else if(cmdcmp(p, "local_zones", 11)) {
|
||||
do_zones_add(ssl, worker->daemon->local_zones);
|
||||
} else if(cmdcmp(p, "local_data_remove", 17)) {
|
||||
do_data_remove(ssl, worker->daemon->local_zones, skipwhite(p+17));
|
||||
} else if(cmdcmp(p, "local_datas_remove", 18)) {
|
||||
do_datas_remove(ssl, worker->daemon->local_zones);
|
||||
} else if(cmdcmp(p, "local_data", 10)) {
|
||||
do_data_add(ssl, worker->daemon->local_zones, skipwhite(p+10));
|
||||
} else if(cmdcmp(p, "local_datas", 11)) {
|
||||
do_datas_add(ssl, worker->daemon->local_zones);
|
||||
} else if(cmdcmp(p, "forward_add", 11)) {
|
||||
do_forward_add(ssl, worker, skipwhite(p+11));
|
||||
} else if(cmdcmp(p, "forward_remove", 14)) {
|
||||
do_forward_remove(ssl, worker, skipwhite(p+14));
|
||||
} else if(cmdcmp(p, "forward", 7)) {
|
||||
do_forward(ssl, worker, skipwhite(p+7));
|
||||
} else if(cmdcmp(p, "stub_add", 8)) {
|
||||
do_stub_add(ssl, worker, skipwhite(p+8));
|
||||
} else if(cmdcmp(p, "stub_remove", 11)) {
|
||||
do_stub_remove(ssl, worker, skipwhite(p+11));
|
||||
} else if(cmdcmp(p, "view_local_zone_remove", 22)) {
|
||||
do_view_zone_remove(ssl, worker, skipwhite(p+22));
|
||||
} else if(cmdcmp(p, "view_local_zone", 15)) {
|
||||
do_view_zone_add(ssl, worker, skipwhite(p+15));
|
||||
} else if(cmdcmp(p, "view_local_data_remove", 22)) {
|
||||
do_view_data_remove(ssl, worker, skipwhite(p+22));
|
||||
} else if(cmdcmp(p, "view_local_datas_remove", 23)){
|
||||
do_view_datas_remove(ssl, worker, skipwhite(p+23));
|
||||
} else if(cmdcmp(p, "view_local_data", 15)) {
|
||||
do_view_data_add(ssl, worker, skipwhite(p+15));
|
||||
} else if(cmdcmp(p, "view_local_datas", 16)) {
|
||||
do_view_datas_add(ssl, worker, skipwhite(p+16));
|
||||
} else if(cmdcmp(p, "flush_zone", 10)) {
|
||||
do_flush_zone(ssl, worker, skipwhite(p+10));
|
||||
} else if(cmdcmp(p, "flush_type", 10)) {
|
||||
@@ -3176,13 +3384,13 @@ execute_cmd(struct daemon_remote* rc, RES* ssl, char* cmd,
|
||||
} else if(cmdcmp(p, "get_option", 10)) {
|
||||
do_get_option(ssl, worker, skipwhite(p+10));
|
||||
} else if(cmdcmp(p, "flush_bogus", 11)) {
|
||||
do_flush_bogus(ssl, worker);
|
||||
do_flush_bogus(ssl, worker, skipwhite(p+11));
|
||||
} else if(cmdcmp(p, "flush_negative", 14)) {
|
||||
do_flush_negative(ssl, worker);
|
||||
} else if(cmdcmp(p, "rpz_enable", 10)) {
|
||||
do_rpz_enable(ssl, worker, skipwhite(p+10));
|
||||
} else if(cmdcmp(p, "rpz_disable", 11)) {
|
||||
do_rpz_disable(ssl, worker, skipwhite(p+11));
|
||||
do_flush_negative(ssl, worker, skipwhite(p+14));
|
||||
} else if(cmdcmp(p, "rpz_enable", 10)) {
|
||||
do_rpz_enable(ssl, worker, skipwhite(p+10));
|
||||
} else if(cmdcmp(p, "rpz_disable", 11)) {
|
||||
do_rpz_disable(ssl, worker, skipwhite(p+11));
|
||||
} else {
|
||||
(void)ssl_printf(ssl, "error unknown command '%s'\n", p);
|
||||
}
|
||||
@@ -3210,7 +3418,7 @@ handle_req(struct daemon_remote* rc, struct rc_state* s, RES* res)
|
||||
int r;
|
||||
char pre[10];
|
||||
char magic[7];
|
||||
char buf[1024];
|
||||
char buf[MAX_CMD_STRLINE];
|
||||
#ifdef USE_WINSOCK
|
||||
/* makes it possible to set the socket blocking again. */
|
||||
/* basically removes it from winsock_event ... */
|
||||
@@ -3222,9 +3430,10 @@ handle_req(struct daemon_remote* rc, struct rc_state* s, RES* res)
|
||||
if(res->ssl) {
|
||||
ERR_clear_error();
|
||||
if((r=SSL_read(res->ssl, magic, (int)sizeof(magic)-1)) <= 0) {
|
||||
if(SSL_get_error(res->ssl, r) == SSL_ERROR_ZERO_RETURN)
|
||||
int r2;
|
||||
if((r2=SSL_get_error(res->ssl, r)) == SSL_ERROR_ZERO_RETURN)
|
||||
return;
|
||||
log_crypto_err("could not SSL_read");
|
||||
log_crypto_err_io("could not SSL_read", r2);
|
||||
return;
|
||||
}
|
||||
} else {
|
||||
@@ -3291,7 +3500,7 @@ remote_handshake_later(struct daemon_remote* rc, struct rc_state* s,
|
||||
log_err("remote control connection closed prematurely");
|
||||
log_addr(VERB_OPS, "failed connection from",
|
||||
&s->c->repinfo.remote_addr, s->c->repinfo.remote_addrlen);
|
||||
log_crypto_err("remote control failed ssl");
|
||||
log_crypto_err_io("remote control failed ssl", r2);
|
||||
clean_point(rc, s);
|
||||
}
|
||||
return 0;
|
||||
|
||||
+8
-1
@@ -391,6 +391,13 @@ void server_stats_obtain(struct worker* worker, struct worker* who,
|
||||
else worker_send_cmd(who, worker_cmd_stats_noreset);
|
||||
verbose(VERB_ALGO, "wait for stats reply");
|
||||
if(tube_wait_timeout(worker->cmd, STATS_THREAD_WAIT) == 0) {
|
||||
#if defined(HAVE_PTHREAD) && defined(SIZEOF_PTHREAD_T) && defined(SIZEOF_UNSIGNED_LONG)
|
||||
# if SIZEOF_PTHREAD_T == SIZEOF_UNSIGNED_LONG
|
||||
unsigned long pthid = 0;
|
||||
if(verbosity >= VERB_OPS)
|
||||
memcpy(&pthid, &who->thr_id, sizeof(unsigned long));
|
||||
# endif
|
||||
#endif
|
||||
verbose(VERB_OPS, "no response from thread %d"
|
||||
#ifdef HAVE_GETTID
|
||||
" LWP %u"
|
||||
@@ -407,7 +414,7 @@ void server_stats_obtain(struct worker* worker, struct worker* who,
|
||||
#endif
|
||||
#if defined(HAVE_PTHREAD) && defined(SIZEOF_PTHREAD_T) && defined(SIZEOF_UNSIGNED_LONG)
|
||||
# if SIZEOF_PTHREAD_T == SIZEOF_UNSIGNED_LONG
|
||||
, (unsigned long)*((unsigned long*)&who->thr_id)
|
||||
, pthid
|
||||
# endif
|
||||
#endif
|
||||
);
|
||||
|
||||
+23
-20
@@ -366,9 +366,8 @@ readpid (const char* file)
|
||||
/** write pid to file.
|
||||
* @param pidfile: file name of pid file.
|
||||
* @param pid: pid to write to file.
|
||||
* @return false on failure
|
||||
*/
|
||||
static int
|
||||
static void
|
||||
writepid (const char* pidfile, pid_t pid)
|
||||
{
|
||||
int fd;
|
||||
@@ -383,7 +382,7 @@ writepid (const char* pidfile, pid_t pid)
|
||||
, 0644)) == -1) {
|
||||
log_err("cannot open pidfile %s: %s",
|
||||
pidfile, strerror(errno));
|
||||
return 0;
|
||||
return;
|
||||
}
|
||||
while(count < strlen(pidbuf)) {
|
||||
ssize_t r = write(fd, pidbuf+count, strlen(pidbuf)-count);
|
||||
@@ -393,17 +392,16 @@ writepid (const char* pidfile, pid_t pid)
|
||||
log_err("cannot write to pidfile %s: %s",
|
||||
pidfile, strerror(errno));
|
||||
close(fd);
|
||||
return 0;
|
||||
return;
|
||||
} else if(r == 0) {
|
||||
log_err("cannot write any bytes to pidfile %s: "
|
||||
"write returns 0 bytes written", pidfile);
|
||||
close(fd);
|
||||
return 0;
|
||||
return;
|
||||
}
|
||||
count += r;
|
||||
}
|
||||
close(fd);
|
||||
return 1;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -475,7 +473,11 @@ perform_setup(struct daemon* daemon, struct config_file* cfg, int debug_mode,
|
||||
#endif
|
||||
#ifdef HAVE_GETPWNAM
|
||||
struct passwd *pwd = NULL;
|
||||
#endif
|
||||
|
||||
if(!daemon_privileged(daemon))
|
||||
fatal_exit("could not do privileged setup");
|
||||
#ifdef HAVE_GETPWNAM
|
||||
if(cfg->username && cfg->username[0]) {
|
||||
if((pwd = getpwnam(cfg->username)) == NULL)
|
||||
fatal_exit("user '%s' does not exist.", cfg->username);
|
||||
@@ -545,7 +547,15 @@ perform_setup(struct daemon* daemon, struct config_file* cfg, int debug_mode,
|
||||
cfg, 1);
|
||||
if(!daemon->pidfile)
|
||||
fatal_exit("pidfile alloc: out of memory");
|
||||
checkoldpid(daemon->pidfile, pidinchroot);
|
||||
/* Check old pid if there is no username configured.
|
||||
* With a username, the assumption is that the privilege
|
||||
* drop makes a pidfile not removed when the server stopped
|
||||
* last time. The server does not chown the pidfile for it,
|
||||
* because that creates privilege escape problems, with the
|
||||
* pidfile writable by unprivileged users, but used by
|
||||
* privileged users. */
|
||||
if(!(cfg->username && cfg->username[0]))
|
||||
checkoldpid(daemon->pidfile, pidinchroot);
|
||||
}
|
||||
#endif
|
||||
|
||||
@@ -557,18 +567,7 @@ perform_setup(struct daemon* daemon, struct config_file* cfg, int debug_mode,
|
||||
/* write new pidfile (while still root, so can be outside chroot) */
|
||||
#ifdef HAVE_KILL
|
||||
if(cfg->pidfile && cfg->pidfile[0] && need_pidfile) {
|
||||
if(writepid(daemon->pidfile, getpid())) {
|
||||
if(cfg->username && cfg->username[0] && cfg_uid != (uid_t)-1 &&
|
||||
pidinchroot) {
|
||||
# ifdef HAVE_CHOWN
|
||||
if(chown(daemon->pidfile, cfg_uid, cfg_gid) == -1) {
|
||||
verbose(VERB_QUERY, "cannot chown %u.%u %s: %s",
|
||||
(unsigned)cfg_uid, (unsigned)cfg_gid,
|
||||
daemon->pidfile, strerror(errno));
|
||||
}
|
||||
# endif /* HAVE_CHOWN */
|
||||
}
|
||||
}
|
||||
writepid(daemon->pidfile, getpid());
|
||||
}
|
||||
#else
|
||||
(void)daemon;
|
||||
@@ -746,7 +745,11 @@ run_daemon(const char* cfgfile, int cmdline_verbose, int debug_mode, int need_pi
|
||||
if(daemon->pidfile) {
|
||||
int fd;
|
||||
/* truncate pidfile */
|
||||
fd = open(daemon->pidfile, O_WRONLY | O_TRUNC, 0644);
|
||||
fd = open(daemon->pidfile, O_WRONLY | O_TRUNC
|
||||
#ifdef O_NOFOLLOW
|
||||
| O_NOFOLLOW
|
||||
#endif
|
||||
, 0644);
|
||||
if(fd != -1)
|
||||
close(fd);
|
||||
/* delete pidfile */
|
||||
|
||||
+203
-200
@@ -66,6 +66,7 @@
|
||||
#include "util/data/msgencode.h"
|
||||
#include "util/data/dname.h"
|
||||
#include "util/fptr_wlist.h"
|
||||
#include "util/proxy_protocol.h"
|
||||
#include "util/tube.h"
|
||||
#include "util/edns.h"
|
||||
#include "util/timeval_func.h"
|
||||
@@ -542,6 +543,8 @@ answer_norec_from_cache(struct worker* worker, struct query_info* qinfo,
|
||||
edns->udp_size = EDNS_ADVERTISED_SIZE;
|
||||
edns->ext_rcode = 0;
|
||||
edns->bits &= EDNS_DO;
|
||||
if(worker->env.cfg->disable_edns_do && (edns->bits & EDNS_DO))
|
||||
edns->edns_present = 0;
|
||||
if(!inplace_cb_reply_cache_call(&worker->env, qinfo, NULL, msg->rep,
|
||||
(int)(flags&LDNS_RCODE_MASK), edns, repinfo, worker->scratchpad,
|
||||
worker->env.now_tv))
|
||||
@@ -656,7 +659,12 @@ answer_from_cache(struct worker* worker, struct query_info* qinfo,
|
||||
if(rep->ttl < timenow) {
|
||||
/* Check if we need to serve expired now */
|
||||
if(worker->env.cfg->serve_expired &&
|
||||
!worker->env.cfg->serve_expired_client_timeout) {
|
||||
!worker->env.cfg->serve_expired_client_timeout
|
||||
#ifdef USE_CACHEDB
|
||||
&& !(worker->env.cachedb_enabled &&
|
||||
worker->env.cfg->cachedb_check_when_serve_expired)
|
||||
#endif
|
||||
) {
|
||||
if(worker->env.cfg->serve_expired_ttl &&
|
||||
rep->serve_expired_ttl < timenow)
|
||||
return 0;
|
||||
@@ -702,6 +710,8 @@ answer_from_cache(struct worker* worker, struct query_info* qinfo,
|
||||
edns->udp_size = EDNS_ADVERTISED_SIZE;
|
||||
edns->ext_rcode = 0;
|
||||
edns->bits &= EDNS_DO;
|
||||
if(worker->env.cfg->disable_edns_do && (edns->bits & EDNS_DO))
|
||||
edns->edns_present = 0;
|
||||
if(!inplace_cb_reply_servfail_call(&worker->env, qinfo, NULL, rep,
|
||||
LDNS_RCODE_SERVFAIL, edns, repinfo, worker->scratchpad,
|
||||
worker->env.now_tv))
|
||||
@@ -742,6 +752,8 @@ answer_from_cache(struct worker* worker, struct query_info* qinfo,
|
||||
edns->udp_size = EDNS_ADVERTISED_SIZE;
|
||||
edns->ext_rcode = 0;
|
||||
edns->bits &= EDNS_DO;
|
||||
if(worker->env.cfg->disable_edns_do && (edns->bits & EDNS_DO))
|
||||
edns->edns_present = 0;
|
||||
*alias_rrset = NULL; /* avoid confusion if caller set it to non-NULL */
|
||||
if((worker->daemon->use_response_ip || worker->daemon->use_rpz) &&
|
||||
!partial_rep && !apply_respip_action(worker, qinfo, cinfo, rep,
|
||||
@@ -1099,6 +1111,172 @@ answer_notify(struct worker* w, struct query_info* qinfo,
|
||||
LDNS_OPCODE_SET(sldns_buffer_begin(pkt), LDNS_PACKET_NOTIFY);
|
||||
}
|
||||
|
||||
static int
|
||||
make_ede_error(struct comm_point* c, struct worker* worker,
|
||||
struct comm_reply* repinfo, int rcode, int16_t ede_code,
|
||||
int ede, struct check_request_result* check_result)
|
||||
{
|
||||
size_t opt_rr_mark;
|
||||
|
||||
if(worker->stats.extended)
|
||||
worker->stats.unwanted_queries++;
|
||||
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);
|
||||
return 1;
|
||||
}
|
||||
comm_point_drop_reply(repinfo);
|
||||
return 0;
|
||||
}
|
||||
/* worker_check_request() above guarantees that the buffer contains at
|
||||
* least a header and that qdcount == 1
|
||||
*/
|
||||
log_assert(sldns_buffer_limit(c->buffer) >= LDNS_HEADER_SIZE
|
||||
&& LDNS_QDCOUNT(sldns_buffer_begin(c->buffer)) == 1);
|
||||
|
||||
sldns_buffer_set_position(c->buffer, LDNS_HEADER_SIZE); /* skip header */
|
||||
|
||||
/* 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), rcode);
|
||||
sldns_buffer_set_position(c->buffer, LDNS_HEADER_SIZE);
|
||||
sldns_buffer_flip(c->buffer);
|
||||
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);
|
||||
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);
|
||||
return 1;
|
||||
}
|
||||
LDNS_QR_SET(sldns_buffer_begin(c->buffer));
|
||||
LDNS_RCODE_SET(sldns_buffer_begin(c->buffer), rcode);
|
||||
|
||||
sldns_buffer_skip(c->buffer, (ssize_t)sizeof(uint16_t)); /* skip qtype */
|
||||
|
||||
sldns_buffer_skip(c->buffer, (ssize_t)sizeof(uint16_t)); /* skip qclass */
|
||||
|
||||
/* The OPT RR to be returned should come directly after
|
||||
* the query, so mark this spot.
|
||||
*/
|
||||
opt_rr_mark = sldns_buffer_position(c->buffer);
|
||||
|
||||
/* Skip through the RR records */
|
||||
if(LDNS_ANCOUNT(sldns_buffer_begin(c->buffer)) != 0 ||
|
||||
LDNS_NSCOUNT(sldns_buffer_begin(c->buffer)) != 0) {
|
||||
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);
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
/* Do we have a valid OPT RR here? If not return rcode (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);
|
||||
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);
|
||||
return 1;
|
||||
}
|
||||
/* Write OPT RR directly after the query,
|
||||
* so without the (possibly skipped) Answer and NS RRs
|
||||
*/
|
||||
LDNS_ANCOUNT_SET(sldns_buffer_begin(c->buffer), 0);
|
||||
LDNS_NSCOUNT_SET(sldns_buffer_begin(c->buffer), 0);
|
||||
sldns_buffer_clear(c->buffer); /* reset write limit */
|
||||
sldns_buffer_set_position(c->buffer, opt_rr_mark);
|
||||
|
||||
/* Check if OPT record can be written
|
||||
* 17 == root label (1) + RR type (2) + UDP Size (2)
|
||||
* + Fields (4) + rdata len (2) + EDE Option code (2)
|
||||
* + EDE Option length (2) + EDE info-code (2)
|
||||
*/
|
||||
if (sldns_buffer_available(c->buffer, 17) == 0) {
|
||||
LDNS_ARCOUNT_SET(sldns_buffer_begin(c->buffer), 0);
|
||||
sldns_buffer_flip(c->buffer);
|
||||
return 1;
|
||||
}
|
||||
|
||||
LDNS_ARCOUNT_SET(sldns_buffer_begin(c->buffer), 1);
|
||||
|
||||
/* root label */
|
||||
sldns_buffer_write_u8(c->buffer, 0);
|
||||
sldns_buffer_write_u16(c->buffer, LDNS_RR_TYPE_OPT);
|
||||
sldns_buffer_write_u16(c->buffer, EDNS_ADVERTISED_SIZE);
|
||||
|
||||
/* write OPT Record TTL Field */
|
||||
sldns_buffer_write_u32(c->buffer, 0);
|
||||
|
||||
/* write rdata len: EDE option + length + info-code */
|
||||
sldns_buffer_write_u16(c->buffer, 6);
|
||||
|
||||
/* write OPTIONS; add EDE option code */
|
||||
sldns_buffer_write_u16(c->buffer, LDNS_EDNS_EDE);
|
||||
|
||||
/* write single EDE option length (for just 1 info-code) */
|
||||
sldns_buffer_write_u16(c->buffer, 2);
|
||||
|
||||
/* write single EDE info-code */
|
||||
sldns_buffer_write_u16(c->buffer, ede_code);
|
||||
|
||||
sldns_buffer_flip(c->buffer);
|
||||
|
||||
verbose(VERB_ALGO, "attached EDE code: %d", ede_code);
|
||||
|
||||
return 1;
|
||||
|
||||
|
||||
}
|
||||
|
||||
static int
|
||||
deny_refuse(struct comm_point* c, enum acl_access acl,
|
||||
enum acl_access deny, enum acl_access refuse,
|
||||
@@ -1117,173 +1295,14 @@ deny_refuse(struct comm_point* c, enum acl_access acl,
|
||||
worker->stats.unwanted_queries++;
|
||||
return 0;
|
||||
} else if(acl == refuse) {
|
||||
size_t opt_rr_mark;
|
||||
|
||||
if(verbosity >= VERB_ALGO) {
|
||||
log_acl_action("refused", &repinfo->client_addr,
|
||||
repinfo->client_addrlen, acl, acladdr);
|
||||
log_buf(VERB_ALGO, "refuse", c->buffer);
|
||||
}
|
||||
|
||||
if(worker->stats.extended)
|
||||
worker->stats.unwanted_queries++;
|
||||
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);
|
||||
return 1;
|
||||
}
|
||||
comm_point_drop_reply(repinfo);
|
||||
return 0;
|
||||
}
|
||||
/* worker_check_request() above guarantees that the buffer contains at
|
||||
* least a header and that qdcount == 1
|
||||
*/
|
||||
log_assert(sldns_buffer_limit(c->buffer) >= LDNS_HEADER_SIZE
|
||||
&& LDNS_QDCOUNT(sldns_buffer_begin(c->buffer)) == 1);
|
||||
|
||||
sldns_buffer_skip(c->buffer, LDNS_HEADER_SIZE); /* skip header */
|
||||
|
||||
/* 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_flip(c->buffer);
|
||||
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);
|
||||
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);
|
||||
return 1;
|
||||
}
|
||||
LDNS_QR_SET(sldns_buffer_begin(c->buffer));
|
||||
LDNS_RCODE_SET(sldns_buffer_begin(c->buffer),
|
||||
LDNS_RCODE_REFUSED);
|
||||
|
||||
sldns_buffer_skip(c->buffer, (ssize_t)sizeof(uint16_t)); /* skip qtype */
|
||||
|
||||
sldns_buffer_skip(c->buffer, (ssize_t)sizeof(uint16_t)); /* skip qclass */
|
||||
|
||||
/* The OPT RR to be returned should come directly after
|
||||
* the query, so mark this spot.
|
||||
*/
|
||||
opt_rr_mark = sldns_buffer_position(c->buffer);
|
||||
|
||||
/* Skip through the RR records */
|
||||
if(LDNS_ANCOUNT(sldns_buffer_begin(c->buffer)) != 0 ||
|
||||
LDNS_NSCOUNT(sldns_buffer_begin(c->buffer)) != 0) {
|
||||
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);
|
||||
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);
|
||||
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);
|
||||
return 1;
|
||||
}
|
||||
/* Write OPT RR directly after the query,
|
||||
* so without the (possibly skipped) Answer and NS RRs
|
||||
*/
|
||||
LDNS_ANCOUNT_SET(sldns_buffer_begin(c->buffer), 0);
|
||||
LDNS_NSCOUNT_SET(sldns_buffer_begin(c->buffer), 0);
|
||||
sldns_buffer_clear(c->buffer); /* reset write limit */
|
||||
sldns_buffer_set_position(c->buffer, opt_rr_mark);
|
||||
|
||||
/* Check if OPT record can be written
|
||||
* 17 == root label (1) + RR type (2) + UDP Size (2)
|
||||
* + Fields (4) + rdata len (2) + EDE Option code (2)
|
||||
* + EDE Option length (2) + EDE info-code (2)
|
||||
*/
|
||||
if (sldns_buffer_available(c->buffer, 17) == 0) {
|
||||
LDNS_ARCOUNT_SET(sldns_buffer_begin(c->buffer), 0);
|
||||
sldns_buffer_flip(c->buffer);
|
||||
return 1;
|
||||
}
|
||||
|
||||
LDNS_ARCOUNT_SET(sldns_buffer_begin(c->buffer), 1);
|
||||
|
||||
/* root label */
|
||||
sldns_buffer_write_u8(c->buffer, 0);
|
||||
sldns_buffer_write_u16(c->buffer, LDNS_RR_TYPE_OPT);
|
||||
sldns_buffer_write_u16(c->buffer, EDNS_ADVERTISED_SIZE);
|
||||
|
||||
/* write OPT Record TTL Field */
|
||||
sldns_buffer_write_u32(c->buffer, 0);
|
||||
|
||||
/* write rdata len: EDE option + length + info-code */
|
||||
sldns_buffer_write_u16(c->buffer, 6);
|
||||
|
||||
/* write OPTIONS; add EDE option code */
|
||||
sldns_buffer_write_u16(c->buffer, LDNS_EDNS_EDE);
|
||||
|
||||
/* write single EDE option length (for just 1 info-code) */
|
||||
sldns_buffer_write_u16(c->buffer, 2);
|
||||
|
||||
/* write single EDE info-code */
|
||||
sldns_buffer_write_u16(c->buffer, LDNS_EDE_PROHIBITED);
|
||||
|
||||
sldns_buffer_flip(c->buffer);
|
||||
|
||||
verbose(VERB_ALGO, "attached EDE code: %d", LDNS_EDE_PROHIBITED);
|
||||
|
||||
return 1;
|
||||
|
||||
return make_ede_error(c, worker, repinfo, LDNS_RCODE_REFUSED,
|
||||
LDNS_EDE_PROHIBITED, ede, check_result);
|
||||
}
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
@@ -1319,15 +1338,6 @@ deny_refuse_non_local(struct comm_point* c, enum acl_access acl,
|
||||
worker, repinfo, acladdr, ede, check_result);
|
||||
}
|
||||
|
||||
/* Returns 1 if the ip rate limit check can happen before EDNS parsing,
|
||||
* else 0 */
|
||||
static int
|
||||
pre_edns_ip_ratelimit_check(enum acl_access acl)
|
||||
{
|
||||
if(acl == acl_allow_cookie) return 0;
|
||||
return 1;
|
||||
}
|
||||
|
||||
/* Check if the query is blocked by source IP rate limiting.
|
||||
* Returns 1 if it passes the check, 0 otherwise. */
|
||||
static int
|
||||
@@ -1455,8 +1465,8 @@ worker_handle_request(struct comm_point* c, void* arg, int error,
|
||||
*/
|
||||
if(worker->dtenv.log_client_query_messages) {
|
||||
log_addr(VERB_ALGO, "request from client", &repinfo->client_addr, repinfo->client_addrlen);
|
||||
log_addr(VERB_ALGO, "to local addr", (void*)repinfo->c->socket->addr->ai_addr, repinfo->c->socket->addr->ai_addrlen);
|
||||
dt_msg_send_client_query(&worker->dtenv, &repinfo->client_addr, (void*)repinfo->c->socket->addr->ai_addr, c->type, c->buffer,
|
||||
log_addr(VERB_ALGO, "to local addr", (void*)repinfo->c->socket->addr, repinfo->c->socket->addrlen);
|
||||
dt_msg_send_client_query(&worker->dtenv, &repinfo->client_addr, (void*)repinfo->c->socket->addr, c->type, c->ssl, c->buffer,
|
||||
((worker->env.cfg->sock_queue_timeout && timeval_isset(&c->recv_tv))?&c->recv_tv:NULL));
|
||||
}
|
||||
#endif
|
||||
@@ -1491,7 +1501,9 @@ worker_handle_request(struct comm_point* c, void* arg, int error,
|
||||
}
|
||||
|
||||
worker->stats.num_queries++;
|
||||
pre_edns_ip_ratelimit = pre_edns_ip_ratelimit_check(acl);
|
||||
pre_edns_ip_ratelimit = !worker->env.cfg->do_answer_cookie
|
||||
|| sldns_buffer_limit(c->buffer) < LDNS_HEADER_SIZE
|
||||
|| LDNS_ARCOUNT(sldns_buffer_begin(c->buffer)) == 0;
|
||||
|
||||
/* If the IP rate limiting check needs extra EDNS information (e.g.,
|
||||
* DNS Cookies) postpone the check until after EDNS is parsed. */
|
||||
@@ -1546,6 +1558,8 @@ worker_handle_request(struct comm_point* c, void* arg, int error,
|
||||
qinfo.qtype == LDNS_RR_TYPE_MAILA ||
|
||||
qinfo.qtype == LDNS_RR_TYPE_MAILB ||
|
||||
(qinfo.qtype >= 128 && qinfo.qtype <= 248)) {
|
||||
size_t opt_rr_mark;
|
||||
|
||||
verbose(VERB_ALGO, "worker request: formerror for meta-type.");
|
||||
log_addr(VERB_CLIENT, "from", &repinfo->client_addr,
|
||||
repinfo->client_addrlen);
|
||||
@@ -1553,14 +1567,12 @@ 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);
|
||||
if(worker->stats.extended) {
|
||||
worker->stats.qtype[qinfo.qtype]++;
|
||||
if (make_ede_error(c, worker, repinfo, LDNS_RCODE_FORMERR,
|
||||
LDNS_EDE_INVALID_QUERY_TYPE,
|
||||
worker->env.cfg->ede, &check_result)) {
|
||||
goto send_reply;
|
||||
}
|
||||
goto send_reply;
|
||||
return 0;
|
||||
}
|
||||
if((ret=parse_edns_from_query_pkt(
|
||||
c->buffer, &edns, worker->env.cfg, c, repinfo,
|
||||
@@ -1942,10 +1954,10 @@ send_reply_rc:
|
||||
/*
|
||||
* sending src (client)/dst (local service) addresses over DNSTAP from send_reply code label (when we serviced local zone for ex.)
|
||||
*/
|
||||
if(worker->dtenv.log_client_response_messages) {
|
||||
log_addr(VERB_ALGO, "from local addr", (void*)repinfo->c->socket->addr->ai_addr, repinfo->c->socket->addr->ai_addrlen);
|
||||
if(worker->dtenv.log_client_response_messages && rc !=0) {
|
||||
log_addr(VERB_ALGO, "from local addr", (void*)repinfo->c->socket->addr, repinfo->c->socket->addrlen);
|
||||
log_addr(VERB_ALGO, "response to client", &repinfo->client_addr, repinfo->client_addrlen);
|
||||
dt_msg_send_client_response(&worker->dtenv, &repinfo->client_addr, (void*)repinfo->c->socket->addr->ai_addr, c->type, c->buffer);
|
||||
dt_msg_send_client_response(&worker->dtenv, &repinfo->client_addr, (void*)repinfo->c->socket->addr, c->type, c->ssl, c->buffer);
|
||||
}
|
||||
#endif
|
||||
if(worker->env.cfg->log_replies)
|
||||
@@ -1959,11 +1971,15 @@ send_reply_rc:
|
||||
qinfo.qname = qinfo.local_alias->rrset->rk.dname;
|
||||
log_reply_info(NO_VERBOSE, &qinfo,
|
||||
&repinfo->client_addr, repinfo->client_addrlen,
|
||||
tv, 1, c->buffer);
|
||||
tv, 1, c->buffer,
|
||||
(worker->env.cfg->log_destaddr?(void*)repinfo->c->socket->addr:NULL),
|
||||
c->type);
|
||||
} else {
|
||||
log_reply_info(NO_VERBOSE, &qinfo,
|
||||
&repinfo->client_addr, repinfo->client_addrlen,
|
||||
tv, 1, c->buffer);
|
||||
tv, 1, c->buffer,
|
||||
(worker->env.cfg->log_destaddr?(void*)repinfo->c->socket->addr:NULL),
|
||||
c->type);
|
||||
}
|
||||
}
|
||||
#ifdef USE_DNSCRYPT
|
||||
@@ -2256,18 +2272,6 @@ worker_init(struct worker* worker, struct config_file *cfg,
|
||||
worker_delete(worker);
|
||||
return 0;
|
||||
}
|
||||
if(!(worker->env.fwds = forwards_create()) ||
|
||||
!forwards_apply_cfg(worker->env.fwds, cfg)) {
|
||||
log_err("Could not set forward zones");
|
||||
worker_delete(worker);
|
||||
return 0;
|
||||
}
|
||||
if(!(worker->env.hints = hints_create()) ||
|
||||
!hints_apply_cfg(worker->env.hints, cfg)) {
|
||||
log_err("Could not set root or stub hints");
|
||||
worker_delete(worker);
|
||||
return 0;
|
||||
}
|
||||
/* one probe timer per process -- if we have 5011 anchors */
|
||||
if(autr_get_num_anchors(worker->env.anchors) > 0
|
||||
#ifndef THREADS_DISABLED
|
||||
@@ -2317,6 +2321,7 @@ worker_init(struct worker* worker, struct config_file *cfg,
|
||||
worker->env.cfg->stat_interval);
|
||||
worker_restart_timer(worker);
|
||||
}
|
||||
pp_init(&sldns_write_uint16, &sldns_write_uint32);
|
||||
return 1;
|
||||
}
|
||||
|
||||
@@ -2339,8 +2344,6 @@ worker_delete(struct worker* worker)
|
||||
outside_network_quit_prepare(worker->back);
|
||||
mesh_delete(worker->env.mesh);
|
||||
sldns_buffer_free(worker->env.scratch_buffer);
|
||||
forwards_delete(worker->env.fwds);
|
||||
hints_delete(worker->env.hints);
|
||||
listen_delete(worker->front);
|
||||
outside_network_delete(worker->back);
|
||||
comm_signal_delete(worker->comsig);
|
||||
|
||||
+58
-43
@@ -573,28 +573,29 @@ static enum module_ext_state
|
||||
handle_event_pass(struct module_qstate* qstate, int id)
|
||||
{
|
||||
struct dns64_qstate* iq = (struct dns64_qstate*)qstate->minfo[id];
|
||||
if (iq && iq->state == DNS64_NEW_QUERY
|
||||
&& qstate->qinfo.qtype == LDNS_RR_TYPE_PTR
|
||||
&& qstate->qinfo.qname_len == 74
|
||||
&& !strcmp((char*)&qstate->qinfo.qname[64], "\03ip6\04arpa"))
|
||||
/* Handle PTR queries for IPv6 addresses. */
|
||||
return handle_ipv6_ptr(qstate, id);
|
||||
int synth_all_cfg = qstate->env->cfg->dns64_synthall;
|
||||
int synth_qname = 0;
|
||||
|
||||
if (qstate->env->cfg->dns64_synthall &&
|
||||
iq && iq->state == DNS64_NEW_QUERY
|
||||
&& qstate->qinfo.qtype == LDNS_RR_TYPE_AAAA)
|
||||
return generate_type_A_query(qstate, id);
|
||||
if(iq && iq->state == DNS64_NEW_QUERY
|
||||
&& qstate->qinfo.qtype == LDNS_RR_TYPE_PTR
|
||||
&& qstate->qinfo.qname_len == 74
|
||||
&& !strcmp((char*)&qstate->qinfo.qname[64], "\03ip6\04arpa")) {
|
||||
/* Handle PTR queries for IPv6 addresses. */
|
||||
return handle_ipv6_ptr(qstate, id);
|
||||
}
|
||||
|
||||
if(dns64_always_synth_for_qname(qstate, id) &&
|
||||
iq && iq->state == DNS64_NEW_QUERY
|
||||
&& !(qstate->query_flags & BIT_CD)
|
||||
&& qstate->qinfo.qtype == LDNS_RR_TYPE_AAAA) {
|
||||
verbose(VERB_ALGO, "dns64: ignore-aaaa and synthesize anyway");
|
||||
if(iq && iq->state == DNS64_NEW_QUERY &&
|
||||
qstate->qinfo.qtype == LDNS_RR_TYPE_AAAA &&
|
||||
(synth_all_cfg ||
|
||||
(synth_qname=(dns64_always_synth_for_qname(qstate, id)
|
||||
&& !(qstate->query_flags & BIT_CD))))) {
|
||||
if(synth_qname)
|
||||
verbose(VERB_ALGO, "dns64: ignore-aaaa and synthesize anyway");
|
||||
return generate_type_A_query(qstate, id);
|
||||
}
|
||||
|
||||
/* We are finished when our sub-query is finished. */
|
||||
if (iq && iq->state == DNS64_SUBQUERY_FINISHED)
|
||||
if(iq && iq->state == DNS64_SUBQUERY_FINISHED)
|
||||
return module_finished;
|
||||
|
||||
/* Otherwise, pass request to next module. */
|
||||
@@ -627,32 +628,37 @@ handle_event_moddone(struct module_qstate* qstate, int id)
|
||||
* synthesize in (sec 5.1.2 of RFC6147).
|
||||
* - A successful AAAA query with an answer.
|
||||
*/
|
||||
if((!iq || iq->state != DNS64_INTERNAL_QUERY)
|
||||
&& qstate->qinfo.qtype == LDNS_RR_TYPE_AAAA
|
||||
&& !(qstate->query_flags & BIT_CD)
|
||||
&& !(qstate->return_msg &&
|
||||
qstate->return_msg->rep &&
|
||||
reply_find_answer_rrset(&qstate->qinfo,
|
||||
qstate->return_msg->rep)))
|
||||
/* not internal, type AAAA, not CD, and no answer RRset,
|
||||
* So, this is a AAAA noerror/nodata answer */
|
||||
return generate_type_A_query(qstate, id);
|
||||
|
||||
if((!iq || iq->state != DNS64_INTERNAL_QUERY)
|
||||
&& qstate->qinfo.qtype == LDNS_RR_TYPE_AAAA
|
||||
&& !(qstate->query_flags & BIT_CD)
|
||||
&& dns64_always_synth_for_qname(qstate, id)) {
|
||||
/* if it is not internal, AAAA, not CD and listed domain,
|
||||
* generate from A record and ignore AAAA */
|
||||
verbose(VERB_ALGO, "dns64: ignore-aaaa and synthesize anyway");
|
||||
/* When an AAAA query completes check if we want to perform DNS64
|
||||
* synthesis. We skip queries with DNSSEC enabled (!CD) and
|
||||
* ones generated by us to retrive the A/PTR record to use for
|
||||
* synth. */
|
||||
int could_synth =
|
||||
qstate->qinfo.qtype == LDNS_RR_TYPE_AAAA &&
|
||||
(!iq || iq->state != DNS64_INTERNAL_QUERY) &&
|
||||
!(qstate->query_flags & BIT_CD);
|
||||
int has_data = /* whether query returned non-empty rrset */
|
||||
qstate->return_msg &&
|
||||
qstate->return_msg->rep &&
|
||||
reply_find_answer_rrset(&qstate->qinfo, qstate->return_msg->rep);
|
||||
int synth_qname = 0;
|
||||
|
||||
if(could_synth &&
|
||||
(!has_data ||
|
||||
(synth_qname=dns64_always_synth_for_qname(qstate, id)))) {
|
||||
if(synth_qname)
|
||||
verbose(VERB_ALGO, "dns64: ignore-aaaa and synthesize anyway");
|
||||
return generate_type_A_query(qstate, id);
|
||||
}
|
||||
|
||||
/* Store the response in cache. */
|
||||
if ( (!iq || !iq->started_no_cache_store) &&
|
||||
qstate->return_msg && qstate->return_msg->rep &&
|
||||
!dns_cache_store(qstate->env, &qstate->qinfo, qstate->return_msg->rep,
|
||||
0, 0, 0, NULL, qstate->query_flags, qstate->qstarttime))
|
||||
if( (!iq || !iq->started_no_cache_store) &&
|
||||
qstate->return_msg &&
|
||||
qstate->return_msg->rep &&
|
||||
!dns_cache_store(
|
||||
qstate->env, &qstate->qinfo, qstate->return_msg->rep,
|
||||
0, 0, 0, NULL,
|
||||
qstate->query_flags, qstate->qstarttime))
|
||||
log_err("out of memory");
|
||||
|
||||
/* do nothing */
|
||||
@@ -969,10 +975,19 @@ dns64_inform_super(struct module_qstate* qstate, int id,
|
||||
}
|
||||
super_dq->state = DNS64_SUBQUERY_FINISHED;
|
||||
|
||||
/* If there is no successful answer, we're done. */
|
||||
if (qstate->return_rcode != LDNS_RCODE_NOERROR
|
||||
|| !qstate->return_msg
|
||||
|| !qstate->return_msg->rep) {
|
||||
/* If there is no successful answer, we're done.
|
||||
* Guarantee that we have at least a NOERROR reply further on. */
|
||||
if(qstate->return_rcode != LDNS_RCODE_NOERROR
|
||||
|| !qstate->return_msg
|
||||
|| !qstate->return_msg->rep) {
|
||||
return;
|
||||
}
|
||||
|
||||
/* When no A record is found for synthesis fall back to AAAA again. */
|
||||
if(qstate->qinfo.qtype == LDNS_RR_TYPE_A &&
|
||||
!reply_find_answer_rrset(&qstate->qinfo,
|
||||
qstate->return_msg->rep)) {
|
||||
super_dq->state = DNS64_INTERNAL_QUERY;
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -1029,8 +1044,8 @@ dns64_get_mem(struct module_env* env, int id)
|
||||
*/
|
||||
static struct module_func_block dns64_block = {
|
||||
"dns64",
|
||||
&dns64_init, &dns64_deinit, &dns64_operate, &dns64_inform_super,
|
||||
&dns64_clear, &dns64_get_mem
|
||||
NULL, NULL, &dns64_init, &dns64_deinit, &dns64_operate,
|
||||
&dns64_inform_super, &dns64_clear, &dns64_get_mem
|
||||
};
|
||||
|
||||
/**
|
||||
|
||||
+68
-9
@@ -86,6 +86,31 @@ dt_pack(const Dnstap__Dnstap *d, void **buf, size_t *sz)
|
||||
return 1;
|
||||
}
|
||||
|
||||
/** See if the message is sent due to dnstap sample rate */
|
||||
static int
|
||||
dt_sample_rate_limited(struct dt_env* env)
|
||||
{
|
||||
lock_basic_lock(&env->sample_lock);
|
||||
/* Sampling is every [n] packets. Where n==1, every packet is sent */
|
||||
if(env->sample_rate > 1) {
|
||||
int submit = 0;
|
||||
/* if sampling is engaged... */
|
||||
if (env->sample_rate_count > env->sample_rate) {
|
||||
/* once the count passes the limit */
|
||||
/* submit the message */
|
||||
submit = 1;
|
||||
/* and reset the count */
|
||||
env->sample_rate_count = 0;
|
||||
}
|
||||
/* increment count regardless */
|
||||
env->sample_rate_count++;
|
||||
lock_basic_unlock(&env->sample_lock);
|
||||
return !submit;
|
||||
}
|
||||
lock_basic_unlock(&env->sample_lock);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void
|
||||
dt_send(const struct dt_env *env, void *buf, size_t len_buf)
|
||||
{
|
||||
@@ -146,6 +171,7 @@ dt_create(struct config_file* cfg)
|
||||
env = (struct dt_env *) calloc(1, sizeof(struct dt_env));
|
||||
if (!env)
|
||||
return NULL;
|
||||
lock_basic_init(&env->sample_lock);
|
||||
|
||||
env->dtio = dt_io_thread_create();
|
||||
if(!env->dtio) {
|
||||
@@ -241,6 +267,12 @@ dt_apply_cfg(struct dt_env *env, struct config_file *cfg)
|
||||
{
|
||||
verbose(VERB_OPS, "dnstap Message/FORWARDER_RESPONSE enabled");
|
||||
}
|
||||
lock_basic_lock(&env->sample_lock);
|
||||
if((env->sample_rate = (unsigned int)cfg->dnstap_sample_rate))
|
||||
{
|
||||
verbose(VERB_OPS, "dnstap SAMPLE_RATE enabled and set to \"%d\"", (int)env->sample_rate);
|
||||
}
|
||||
lock_basic_unlock(&env->sample_lock);
|
||||
}
|
||||
|
||||
int
|
||||
@@ -273,6 +305,7 @@ dt_delete(struct dt_env *env)
|
||||
if (!env)
|
||||
return;
|
||||
dt_io_thread_delete(env->dtio);
|
||||
lock_basic_destroy(&env->sample_lock);
|
||||
free(env->identity);
|
||||
free(env->version);
|
||||
free(env);
|
||||
@@ -305,6 +338,7 @@ dt_msg_fill_net(struct dt_msg *dm,
|
||||
struct sockaddr_storage *qs,
|
||||
struct sockaddr_storage *rs,
|
||||
enum comm_point_type cptype,
|
||||
void *cpssl,
|
||||
ProtobufCBinaryData *qaddr, protobuf_c_boolean *has_qaddr,
|
||||
uint32_t *qport, protobuf_c_boolean *has_qport,
|
||||
ProtobufCBinaryData *raddr, protobuf_c_boolean *has_raddr,
|
||||
@@ -371,13 +405,26 @@ dt_msg_fill_net(struct dt_msg *dm,
|
||||
*has_rport = 1;
|
||||
}
|
||||
|
||||
log_assert(cptype == comm_udp || cptype == comm_tcp);
|
||||
if (cptype == comm_udp) {
|
||||
/* socket_protocol */
|
||||
dm->m.socket_protocol = DNSTAP__SOCKET_PROTOCOL__UDP;
|
||||
dm->m.has_socket_protocol = 1;
|
||||
} else if (cptype == comm_tcp) {
|
||||
if (cpssl == NULL) {
|
||||
/* socket_protocol */
|
||||
dm->m.socket_protocol = DNSTAP__SOCKET_PROTOCOL__TCP;
|
||||
dm->m.has_socket_protocol = 1;
|
||||
} else {
|
||||
/* socket_protocol */
|
||||
dm->m.socket_protocol = DNSTAP__SOCKET_PROTOCOL__DOT;
|
||||
dm->m.has_socket_protocol = 1;
|
||||
}
|
||||
} else if (cptype == comm_http) {
|
||||
/* socket_protocol */
|
||||
dm->m.socket_protocol = DNSTAP__SOCKET_PROTOCOL__DOH;
|
||||
dm->m.has_socket_protocol = 1;
|
||||
} else {
|
||||
/* other socket protocol */
|
||||
dm->m.socket_protocol = DNSTAP__SOCKET_PROTOCOL__TCP;
|
||||
dm->m.has_socket_protocol = 1;
|
||||
}
|
||||
@@ -388,12 +435,16 @@ dt_msg_send_client_query(struct dt_env *env,
|
||||
struct sockaddr_storage *qsock,
|
||||
struct sockaddr_storage *rsock,
|
||||
enum comm_point_type cptype,
|
||||
void *cpssl,
|
||||
sldns_buffer *qmsg,
|
||||
struct timeval* tstamp)
|
||||
{
|
||||
struct dt_msg dm;
|
||||
struct timeval qtime;
|
||||
|
||||
if(dt_sample_rate_limited(env))
|
||||
return;
|
||||
|
||||
if(tstamp)
|
||||
memcpy(&qtime, tstamp, sizeof(qtime));
|
||||
else gettimeofday(&qtime, NULL);
|
||||
@@ -410,8 +461,7 @@ dt_msg_send_client_query(struct dt_env *env,
|
||||
dt_fill_buffer(qmsg, &dm.m.query_message, &dm.m.has_query_message);
|
||||
|
||||
/* socket_family, socket_protocol, query_address, query_port, response_address, response_port */
|
||||
log_assert(cptype == comm_udp || cptype == comm_tcp);
|
||||
dt_msg_fill_net(&dm, qsock, rsock, cptype,
|
||||
dt_msg_fill_net(&dm, qsock, rsock, cptype, cpssl,
|
||||
&dm.m.query_address, &dm.m.has_query_address,
|
||||
&dm.m.query_port, &dm.m.has_query_port,
|
||||
&dm.m.response_address, &dm.m.has_response_address,
|
||||
@@ -427,11 +477,15 @@ dt_msg_send_client_response(struct dt_env *env,
|
||||
struct sockaddr_storage *qsock,
|
||||
struct sockaddr_storage *rsock,
|
||||
enum comm_point_type cptype,
|
||||
void *cpssl,
|
||||
sldns_buffer *rmsg)
|
||||
{
|
||||
struct dt_msg dm;
|
||||
struct timeval rtime;
|
||||
|
||||
if(dt_sample_rate_limited(env))
|
||||
return;
|
||||
|
||||
gettimeofday(&rtime, NULL);
|
||||
|
||||
/* type */
|
||||
@@ -446,8 +500,7 @@ dt_msg_send_client_response(struct dt_env *env,
|
||||
dt_fill_buffer(rmsg, &dm.m.response_message, &dm.m.has_response_message);
|
||||
|
||||
/* socket_family, socket_protocol, query_address, query_port, response_address, response_port */
|
||||
log_assert(cptype == comm_udp || cptype == comm_tcp);
|
||||
dt_msg_fill_net(&dm, qsock, rsock, cptype,
|
||||
dt_msg_fill_net(&dm, qsock, rsock, cptype, cpssl,
|
||||
&dm.m.query_address, &dm.m.has_query_address,
|
||||
&dm.m.query_port, &dm.m.has_query_port,
|
||||
&dm.m.response_address, &dm.m.has_response_address,
|
||||
@@ -462,6 +515,7 @@ dt_msg_send_outside_query(struct dt_env *env,
|
||||
struct sockaddr_storage *rsock,
|
||||
struct sockaddr_storage *qsock,
|
||||
enum comm_point_type cptype,
|
||||
void *cpssl,
|
||||
uint8_t *zone, size_t zone_len,
|
||||
sldns_buffer *qmsg)
|
||||
{
|
||||
@@ -469,6 +523,9 @@ dt_msg_send_outside_query(struct dt_env *env,
|
||||
struct timeval qtime;
|
||||
uint16_t qflags;
|
||||
|
||||
if(dt_sample_rate_limited(env))
|
||||
return;
|
||||
|
||||
gettimeofday(&qtime, NULL);
|
||||
qflags = sldns_buffer_read_u16_at(qmsg, 2);
|
||||
|
||||
@@ -497,8 +554,7 @@ dt_msg_send_outside_query(struct dt_env *env,
|
||||
dt_fill_buffer(qmsg, &dm.m.query_message, &dm.m.has_query_message);
|
||||
|
||||
/* socket_family, socket_protocol, response_address, response_port, query_address, query_port */
|
||||
log_assert(cptype == comm_udp || cptype == comm_tcp);
|
||||
dt_msg_fill_net(&dm, rsock, qsock, cptype,
|
||||
dt_msg_fill_net(&dm, rsock, qsock, cptype, cpssl,
|
||||
&dm.m.response_address, &dm.m.has_response_address,
|
||||
&dm.m.response_port, &dm.m.has_response_port,
|
||||
&dm.m.query_address, &dm.m.has_query_address,
|
||||
@@ -513,6 +569,7 @@ dt_msg_send_outside_response(struct dt_env *env,
|
||||
struct sockaddr_storage *rsock,
|
||||
struct sockaddr_storage *qsock,
|
||||
enum comm_point_type cptype,
|
||||
void *cpssl,
|
||||
uint8_t *zone, size_t zone_len,
|
||||
uint8_t *qbuf, size_t qbuf_len,
|
||||
const struct timeval *qtime,
|
||||
@@ -522,6 +579,9 @@ dt_msg_send_outside_response(struct dt_env *env,
|
||||
struct dt_msg dm;
|
||||
uint16_t qflags;
|
||||
|
||||
if(dt_sample_rate_limited(env))
|
||||
return;
|
||||
|
||||
(void)qbuf_len; log_assert(qbuf_len >= sizeof(qflags));
|
||||
memcpy(&qflags, qbuf, sizeof(qflags));
|
||||
qflags = ntohs(qflags);
|
||||
@@ -556,8 +616,7 @@ dt_msg_send_outside_response(struct dt_env *env,
|
||||
dt_fill_buffer(rmsg, &dm.m.response_message, &dm.m.has_response_message);
|
||||
|
||||
/* socket_family, socket_protocol, response_address, response_port, query_address, query_port */
|
||||
log_assert(cptype == comm_udp || cptype == comm_tcp);
|
||||
dt_msg_fill_net(&dm, rsock, qsock, cptype,
|
||||
dt_msg_fill_net(&dm, rsock, qsock, cptype, cpssl,
|
||||
&dm.m.response_address, &dm.m.has_response_address,
|
||||
&dm.m.response_port, &dm.m.has_response_port,
|
||||
&dm.m.query_address, &dm.m.has_query_address,
|
||||
|
||||
@@ -39,6 +39,7 @@
|
||||
|
||||
#ifdef USE_DNSTAP
|
||||
|
||||
#include "util/locks.h"
|
||||
struct config_file;
|
||||
struct sldns_buffer;
|
||||
struct dt_msg_queue;
|
||||
@@ -75,6 +76,13 @@ struct dt_env {
|
||||
unsigned log_forwarder_query_messages : 1;
|
||||
/** whether to log Message/FORWARDER_RESPONSE */
|
||||
unsigned log_forwarder_response_messages : 1;
|
||||
|
||||
/** lock on sample count */
|
||||
lock_basic_type sample_lock;
|
||||
/** rate limit value from config, samples 1/N messages */
|
||||
unsigned int sample_rate;
|
||||
/** rate limit counter */
|
||||
unsigned int sample_rate_count;
|
||||
};
|
||||
|
||||
/**
|
||||
@@ -133,6 +141,7 @@ dt_msg_send_client_query(struct dt_env *env,
|
||||
struct sockaddr_storage *qsock,
|
||||
struct sockaddr_storage *rsock,
|
||||
enum comm_point_type cptype,
|
||||
void *cpssl,
|
||||
struct sldns_buffer *qmsg,
|
||||
struct timeval* tstamp);
|
||||
|
||||
@@ -149,6 +158,7 @@ dt_msg_send_client_response(struct dt_env *env,
|
||||
struct sockaddr_storage *qsock,
|
||||
struct sockaddr_storage *rsock,
|
||||
enum comm_point_type cptype,
|
||||
void *cpssl,
|
||||
struct sldns_buffer *rmsg);
|
||||
|
||||
/**
|
||||
@@ -168,6 +178,7 @@ dt_msg_send_outside_query(struct dt_env *env,
|
||||
struct sockaddr_storage *rsock,
|
||||
struct sockaddr_storage *qsock,
|
||||
enum comm_point_type cptype,
|
||||
void *cpssl,
|
||||
uint8_t *zone, size_t zone_len,
|
||||
struct sldns_buffer *qmsg);
|
||||
|
||||
@@ -192,6 +203,7 @@ dt_msg_send_outside_response(struct dt_env *env,
|
||||
struct sockaddr_storage *rsock,
|
||||
struct sockaddr_storage *qsock,
|
||||
enum comm_point_type cptype,
|
||||
void *cpssl,
|
||||
uint8_t *zone, size_t zone_len,
|
||||
uint8_t *qbuf, size_t qbuf_len,
|
||||
const struct timeval *qtime,
|
||||
|
||||
+66
-38
@@ -5,45 +5,73 @@
|
||||
# Check for required dnstap libraries and add dnstap configure args.
|
||||
AC_DEFUN([dt_DNSTAP],
|
||||
[
|
||||
AC_ARG_ENABLE([dnstap],
|
||||
AS_HELP_STRING([--enable-dnstap],
|
||||
[Enable dnstap support (requires protobuf-c)]),
|
||||
[opt_dnstap=$enableval], [opt_dnstap=no])
|
||||
AC_ARG_ENABLE([dnstap],
|
||||
AS_HELP_STRING([--enable-dnstap],
|
||||
[Enable dnstap support (requires protobuf-c)]),
|
||||
[opt_dnstap=$enableval],
|
||||
[opt_dnstap=no])
|
||||
|
||||
AC_ARG_WITH([dnstap-socket-path],
|
||||
AS_HELP_STRING([--with-dnstap-socket-path=pathname],
|
||||
[set default dnstap socket path]),
|
||||
[opt_dnstap_socket_path=$withval], [opt_dnstap_socket_path="$1"])
|
||||
AC_ARG_WITH([dnstap-socket-path],
|
||||
AS_HELP_STRING([--with-dnstap-socket-path=pathname],
|
||||
[set default dnstap socket path]),
|
||||
[opt_dnstap_socket_path=$withval],
|
||||
[opt_dnstap_socket_path="$1"])
|
||||
|
||||
if test "x$opt_dnstap" != "xno"; then
|
||||
AC_PATH_PROG([PROTOC_C], [protoc-c])
|
||||
if test -z "$PROTOC_C"; then
|
||||
AC_MSG_ERROR([The protoc-c program was not found. Please install protobuf-c!])
|
||||
if test "x$opt_dnstap" != "xno"; then
|
||||
AC_PATH_PROG([PROTOC_C], [protoc-c])
|
||||
if test -z "$PROTOC_C"; then
|
||||
AC_MSG_ERROR([The protoc-c program was not found. Please install protobuf-c!])
|
||||
fi
|
||||
AC_ARG_WITH([protobuf-c],
|
||||
AS_HELP_STRING([--with-protobuf-c=path], [Path where protobuf-c is installed, for dnstap]),
|
||||
[
|
||||
# workaround for protobuf-c includes at old dir before protobuf-c-1.0.0
|
||||
if test -f $withval/include/google/protobuf-c/protobuf-c.h; then
|
||||
CFLAGS="$CFLAGS -I$withval/include/google"
|
||||
else
|
||||
CFLAGS="$CFLAGS -I$withval/include"
|
||||
fi
|
||||
LDFLAGS="$LDFLAGS -L$withval/lib"
|
||||
],
|
||||
[
|
||||
if test -n "$PKG_CONFIG"; then
|
||||
PKG_CHECK_MODULES([PROTOBUFC], [libprotobuf-c],
|
||||
[
|
||||
CFLAGS="$CFLAGS $PROTOBUFC_CFLAGS"
|
||||
LIBS="$LIBS $PROTOBUFC_LIBS"
|
||||
],
|
||||
[
|
||||
# pkg-config failed; try falling back to known values
|
||||
# workaround for protobuf-c includes at old dir before protobuf-c-1.0.0
|
||||
if test -f /usr/include/google/protobuf-c/protobuf-c.h; then
|
||||
CFLAGS="$CFLAGS -I/usr/include/google"
|
||||
else
|
||||
if test -f /usr/local/include/google/protobuf-c/protobuf-c.h; then
|
||||
CFLAGS="$CFLAGS -I/usr/local/include/google"
|
||||
LDFLAGS="$LDFLAGS -L/usr/local/lib"
|
||||
else
|
||||
AC_MSG_ERROR([The protobuf-c package was not found with pkg-config. Please install protobuf-c!])
|
||||
fi
|
||||
fi
|
||||
]
|
||||
)
|
||||
else
|
||||
# workaround for protobuf-c includes at old dir before protobuf-c-1.0.0
|
||||
if test -f /usr/include/google/protobuf-c/protobuf-c.h; then
|
||||
CFLAGS="$CFLAGS -I/usr/include/google"
|
||||
else
|
||||
if test -f /usr/local/include/google/protobuf-c/protobuf-c.h; then
|
||||
CFLAGS="$CFLAGS -I/usr/local/include/google"
|
||||
LDFLAGS="$LDFLAGS -L/usr/local/lib"
|
||||
fi
|
||||
fi
|
||||
fi
|
||||
]
|
||||
)
|
||||
AC_SEARCH_LIBS([protobuf_c_message_pack], [protobuf-c], [],
|
||||
AC_MSG_ERROR([The protobuf-c library was not found. Please install the development libraries for protobuf-c!]))
|
||||
$2
|
||||
else
|
||||
$3
|
||||
fi
|
||||
AC_ARG_WITH([protobuf-c], AS_HELP_STRING([--with-protobuf-c=path],
|
||||
[Path where protobuf-c is installed, for dnstap]), [
|
||||
# workaround for protobuf-c includes at old dir before protobuf-c-1.0.0
|
||||
if test -f $withval/include/google/protobuf-c/protobuf-c.h; then
|
||||
CFLAGS="$CFLAGS -I$withval/include/google"
|
||||
else
|
||||
CFLAGS="$CFLAGS -I$withval/include"
|
||||
fi
|
||||
LDFLAGS="$LDFLAGS -L$withval/lib"
|
||||
], [
|
||||
# workaround for protobuf-c includes at old dir before protobuf-c-1.0.0
|
||||
if test -f /usr/include/google/protobuf-c/protobuf-c.h; then
|
||||
CFLAGS="$CFLAGS -I/usr/include/google"
|
||||
else
|
||||
if test -f /usr/local/include/google/protobuf-c/protobuf-c.h; then
|
||||
CFLAGS="$CFLAGS -I/usr/local/include/google"
|
||||
LDFLAGS="$LDFLAGS -L/usr/local/lib"
|
||||
fi
|
||||
fi
|
||||
])
|
||||
AC_SEARCH_LIBS([protobuf_c_message_pack], [protobuf-c], [],
|
||||
AC_MSG_ERROR([The protobuf-c library was not found. Please install protobuf-c!]))
|
||||
$2
|
||||
else
|
||||
$3
|
||||
fi
|
||||
])
|
||||
|
||||
+75
-7
@@ -13,8 +13,8 @@
|
||||
// with this file. If not, see:
|
||||
//
|
||||
// <http://creativecommons.org/publicdomain/zero/1.0/>.
|
||||
syntax = "proto2";
|
||||
|
||||
syntax = "proto2";
|
||||
package dnstap;
|
||||
|
||||
// "Dnstap": this is the top-level dnstap type, which is a "union" type that
|
||||
@@ -56,11 +56,60 @@ enum SocketFamily {
|
||||
INET6 = 2; // IPv6 (RFC 2460)
|
||||
}
|
||||
|
||||
// SocketProtocol: the transport protocol of a socket. This specifies how to
|
||||
// interpret "transport port" fields.
|
||||
// SocketProtocol: the protocol used to transport a DNS message.
|
||||
enum SocketProtocol {
|
||||
UDP = 1; // User Datagram Protocol (RFC 768)
|
||||
TCP = 2; // Transmission Control Protocol (RFC 793)
|
||||
UDP = 1; // DNS over UDP transport (RFC 1035 section 4.2.1)
|
||||
TCP = 2; // DNS over TCP transport (RFC 1035 section 4.2.2)
|
||||
DOT = 3; // DNS over TLS (RFC 7858)
|
||||
DOH = 4; // DNS over HTTPS (RFC 8484)
|
||||
DNSCryptUDP = 5; // DNSCrypt over UDP (https://dnscrypt.info/protocol)
|
||||
DNSCryptTCP = 6; // DNSCrypt over TCP (https://dnscrypt.info/protocol)
|
||||
DOQ = 7; // DNS over QUIC (RFC 9250)
|
||||
}
|
||||
|
||||
// Policy: information about any name server operator policy
|
||||
// applied to the processing of a DNS message.
|
||||
message Policy {
|
||||
|
||||
// Match: what aspect of the message or message exchange
|
||||
// triggered the application of the Policy.
|
||||
enum Match {
|
||||
QNAME = 1; // Name in question section of query
|
||||
CLIENT_IP = 2; // Client IP address
|
||||
RESPONSE_IP = 3; // Address in A/AAAA RRSet
|
||||
NS_NAME = 4; // Authoritative name server, by name
|
||||
NS_IP = 5; // Authoritative name server, by IP address
|
||||
}
|
||||
|
||||
// The Action taken to implement the Policy.
|
||||
enum Action {
|
||||
NXDOMAIN = 1; // Respond with NXDOMAIN
|
||||
NODATA = 2; // Respond with empty answer section
|
||||
PASS = 3; // Do not alter the response (passthrough)
|
||||
DROP = 4; // Do not respond.
|
||||
TRUNCATE = 5; // Truncate UDP response, forcing TCP retry
|
||||
LOCAL_DATA = 6; // Respond with local data from policy
|
||||
}
|
||||
|
||||
// type: the type of policy applied, e.g. "RPZ" for a
|
||||
// policy from a Response Policy Zone.
|
||||
optional string type = 1;
|
||||
|
||||
// rule: the rule matched by the message.
|
||||
//
|
||||
// In a RPZ context, this is the owner name of the rule in
|
||||
// the Reponse Policy Zone in wire format.
|
||||
optional bytes rule = 2;
|
||||
|
||||
// action: the policy action taken in response to the
|
||||
// rule match.
|
||||
optional Action action = 3;
|
||||
|
||||
// match: the feature of the message exchange which matched the rule.
|
||||
optional Match match = 4;
|
||||
|
||||
// The matched value. Format depends on the matched feature .
|
||||
optional bytes value = 5;
|
||||
}
|
||||
|
||||
// Message: a wire-format (RFC 1035 section 4) DNS message and associated
|
||||
@@ -158,6 +207,24 @@ message Message {
|
||||
// STUB_RESPONSE is a DNS response message sent from a DNS server to a
|
||||
// stub resolver, from the perspective of the stub resolver.
|
||||
STUB_RESPONSE = 10;
|
||||
|
||||
// TOOL_QUERY is a DNS query message sent from a DNS software tool to a
|
||||
// DNS server, from the perspective of the tool.
|
||||
TOOL_QUERY = 11;
|
||||
|
||||
// TOOL_RESPONSE is a DNS response message received by a DNS software
|
||||
// tool from a DNS server, from the perspective of the tool.
|
||||
TOOL_RESPONSE = 12;
|
||||
|
||||
// UPDATE_QUERY is a Dynamic DNS Update request (RFC 2136) received
|
||||
// by an authoritative name server, from the perspective of the
|
||||
// authoritative name server.
|
||||
UPDATE_QUERY = 13;
|
||||
|
||||
// UPDATE_RESPONSE is a Dynamic DNS Update response (RFC 2136) sent
|
||||
// from an authoritative name server, from the perspective of the
|
||||
// authoritative name server.
|
||||
UPDATE_RESPONSE = 14;
|
||||
}
|
||||
|
||||
// One of the Type values described above.
|
||||
@@ -215,6 +282,9 @@ message Message {
|
||||
|
||||
// The responder's original wire-format DNS response message, verbatim.
|
||||
optional bytes response_message = 14;
|
||||
|
||||
// Operator policy applied to the processing of this message, if any.
|
||||
optional Policy policy = 15;
|
||||
}
|
||||
|
||||
// All fields except for 'type' in the Message schema are optional.
|
||||
@@ -236,7 +306,6 @@ message Message {
|
||||
|
||||
// RESOLVER_QUERY:
|
||||
// socket_family, socket_protocol
|
||||
// query_name, query_type, query_class
|
||||
// query_message
|
||||
// query_time_sec, query_time_nsec
|
||||
// query_zone
|
||||
@@ -244,7 +313,6 @@ message Message {
|
||||
|
||||
// RESOLVER_RESPONSE:
|
||||
// socket_family, socket_protocol
|
||||
// query_name, query_type, query_class
|
||||
// query_time_sec, query_time_nsec
|
||||
// query_zone
|
||||
// response_address, response_port
|
||||
|
||||
+47
-12
@@ -176,10 +176,7 @@ void
|
||||
mq_wakeup_cb(void* arg)
|
||||
{
|
||||
struct dt_msg_queue* mq = (struct dt_msg_queue*)arg;
|
||||
/* even if the dtio is already active, because perhaps much
|
||||
* traffic suddenly, we leave the timer running to save on
|
||||
* managing it, the once a second timer is less work then
|
||||
* starting and stopping the timer frequently */
|
||||
|
||||
lock_basic_lock(&mq->dtio->wakeup_timer_lock);
|
||||
mq->dtio->wakeup_timer_enabled = 0;
|
||||
lock_basic_unlock(&mq->dtio->wakeup_timer_lock);
|
||||
@@ -210,6 +207,8 @@ dt_msg_queue_start_timer(struct dt_msg_queue* mq, int wakeupnow)
|
||||
lock_basic_lock(&mq->dtio->wakeup_timer_lock);
|
||||
if(mq->dtio->wakeup_timer_enabled) {
|
||||
if(wakeupnow) {
|
||||
tv.tv_sec = 0;
|
||||
tv.tv_usec = 0;
|
||||
comm_timer_set(mq->wakeup_timer, &tv);
|
||||
}
|
||||
lock_basic_unlock(&mq->dtio->wakeup_timer_lock);
|
||||
@@ -221,8 +220,14 @@ dt_msg_queue_start_timer(struct dt_msg_queue* mq, int wakeupnow)
|
||||
if(!wakeupnow) {
|
||||
tv.tv_sec = 1;
|
||||
tv.tv_usec = 0;
|
||||
/* If it is already set, keep it running. */
|
||||
if(!comm_timer_is_set(mq->wakeup_timer))
|
||||
comm_timer_set(mq->wakeup_timer, &tv);
|
||||
} else {
|
||||
tv.tv_sec = 0;
|
||||
tv.tv_usec = 0;
|
||||
comm_timer_set(mq->wakeup_timer, &tv);
|
||||
}
|
||||
comm_timer_set(mq->wakeup_timer, &tv);
|
||||
lock_basic_unlock(&mq->dtio->wakeup_timer_lock);
|
||||
}
|
||||
|
||||
@@ -260,8 +265,9 @@ dt_msg_queue_submit(struct dt_msg_queue* mq, void* buf, size_t len)
|
||||
|
||||
/* acquire lock */
|
||||
lock_basic_lock(&mq->lock);
|
||||
/* if list was empty, start timer for (eventual) wakeup */
|
||||
if(mq->first == NULL)
|
||||
/* if list was empty, start timer for (eventual) wakeup,
|
||||
* or if dtio is not writing now an eventual wakeup is needed. */
|
||||
if(mq->first == NULL || !mq->dtio->event_added_is_write)
|
||||
wakeupstarttimer = 1;
|
||||
/* if list contains more than wakeupnum elements, wakeup now,
|
||||
* or if list is (going to be) almost full */
|
||||
@@ -788,7 +794,7 @@ static int dtio_write_ssl(struct dt_io_thread* dtio, uint8_t* buf,
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
log_crypto_err("dnstap io, could not SSL_write");
|
||||
log_crypto_err_io("dnstap io, could not SSL_write", want);
|
||||
return -1;
|
||||
}
|
||||
return r;
|
||||
@@ -1029,7 +1035,7 @@ static int ssl_read_bytes(struct dt_io_thread* dtio, void* buf, size_t len)
|
||||
"other side");
|
||||
return 0;
|
||||
}
|
||||
log_crypto_err("could not SSL_read");
|
||||
log_crypto_err_io("could not SSL_read", want);
|
||||
verbose(VERB_DETAIL, "dnstap io: output closed by the "
|
||||
"other side");
|
||||
return 0;
|
||||
@@ -1259,6 +1265,13 @@ static void dtio_sleep(struct dt_io_thread* dtio)
|
||||
/* unregister the event polling for write, because there is
|
||||
* nothing to be written */
|
||||
(void)dtio_add_output_event_read(dtio);
|
||||
|
||||
/* Set wakeuptimer enabled off; so that the next worker thread that
|
||||
* wants to log starts a timer if needed, since the writer thread
|
||||
* has gone to sleep. */
|
||||
lock_basic_lock(&dtio->wakeup_timer_lock);
|
||||
dtio->wakeup_timer_enabled = 0;
|
||||
lock_basic_unlock(&dtio->wakeup_timer_lock);
|
||||
}
|
||||
|
||||
#ifdef HAVE_SSL
|
||||
@@ -1322,7 +1335,11 @@ static int dtio_ssl_check_peer(struct dt_io_thread* dtio)
|
||||
if((SSL_get_verify_mode(dtio->ssl)&SSL_VERIFY_PEER)) {
|
||||
/* verification */
|
||||
if(SSL_get_verify_result(dtio->ssl) == X509_V_OK) {
|
||||
#ifdef HAVE_SSL_GET1_PEER_CERTIFICATE
|
||||
X509* x = SSL_get1_peer_certificate(dtio->ssl);
|
||||
#else
|
||||
X509* x = SSL_get_peer_certificate(dtio->ssl);
|
||||
#endif
|
||||
if(!x) {
|
||||
verbose(VERB_ALGO, "dnstap io, %s, SSL "
|
||||
"connection failed no certificate",
|
||||
@@ -1347,7 +1364,11 @@ static int dtio_ssl_check_peer(struct dt_io_thread* dtio)
|
||||
#endif
|
||||
X509_free(x);
|
||||
} else {
|
||||
#ifdef HAVE_SSL_GET1_PEER_CERTIFICATE
|
||||
X509* x = SSL_get1_peer_certificate(dtio->ssl);
|
||||
#else
|
||||
X509* x = SSL_get_peer_certificate(dtio->ssl);
|
||||
#endif
|
||||
if(x) {
|
||||
log_cert(VERB_ALGO, "dnstap io, peer "
|
||||
"certificate", x);
|
||||
@@ -1431,8 +1452,8 @@ static int dtio_ssl_handshake(struct dt_io_thread* dtio,
|
||||
} else {
|
||||
unsigned long err = ERR_get_error();
|
||||
if(!squelch_err_ssl_handshake(err)) {
|
||||
log_crypto_err_code("dnstap io, ssl handshake failed",
|
||||
err);
|
||||
log_crypto_err_io_code("dnstap io, ssl handshake failed",
|
||||
want, err);
|
||||
verbose(VERB_OPS, "dnstap io, ssl handshake failed "
|
||||
"from %s", dtio->ip_str);
|
||||
}
|
||||
@@ -1513,8 +1534,22 @@ void dtio_output_cb(int ATTR_UNUSED(fd), short bits, void* arg)
|
||||
/* no messages on the first iteration,
|
||||
* the queues are all empty */
|
||||
dtio_sleep(dtio);
|
||||
/* After putting to sleep, see if
|
||||
* a message is in a message queue,
|
||||
* if so, resume service. Stops a
|
||||
* race condition where a thread could
|
||||
* have one message but the dtio
|
||||
* also just went to sleep. With the
|
||||
* message queued between the
|
||||
* dtio_find_msg and dtio_sleep
|
||||
* calls. */
|
||||
if(dtio_find_msg(dtio)) {
|
||||
if(!dtio_add_output_event_write(dtio))
|
||||
return;
|
||||
}
|
||||
}
|
||||
return; /* nothing to do */
|
||||
if(!dtio->cur_msg)
|
||||
return; /* nothing to do */
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
+195
-31
@@ -75,17 +75,18 @@
|
||||
static void usage(char* argv[])
|
||||
{
|
||||
printf("usage: %s [options]\n", argv[0]);
|
||||
printf(" Listen to dnstap messages\n");
|
||||
printf(" Listen to dnstap messages\n");
|
||||
printf("stdout has dnstap log, stderr has verbose server log\n");
|
||||
printf("-u <socketpath> listen to unix socket with this file name\n");
|
||||
printf("-s <serverip[@port]> listen for TCP on the IP and port\n");
|
||||
printf("-t <serverip[@port]> listen for TLS on IP and port\n");
|
||||
printf("-x <server.key> server key file for TLS service\n");
|
||||
printf("-y <server.pem> server cert file for TLS service\n");
|
||||
printf("-z <verify.pem> cert file to verify client connections\n");
|
||||
printf("-l long format for DNS printout\n");
|
||||
printf("-v more verbose log output\n");
|
||||
printf("-h this help text\n");
|
||||
printf("-u <socketpath> listen to unix socket with this file name\n");
|
||||
printf("-s <serverip[@port]> listen for TCP on the IP and port\n");
|
||||
printf("-t <serverip[@port]> listen for TLS on IP and port\n");
|
||||
printf("-x <server.key> server key file for TLS service\n");
|
||||
printf("-y <server.pem> server cert file for TLS service\n");
|
||||
printf("-z <verify.pem> cert file to verify client connections\n");
|
||||
printf("-l long format for DNS printout\n");
|
||||
printf("-v more verbose log output\n");
|
||||
printf("-c internal unit test and exit\n");
|
||||
printf("-h this help text\n");
|
||||
exit(1);
|
||||
}
|
||||
|
||||
@@ -102,6 +103,14 @@ struct main_tap_data {
|
||||
struct tap_socket_list* acceptlist;
|
||||
};
|
||||
|
||||
/* list of data */
|
||||
struct tap_data_list {
|
||||
/** next in list */
|
||||
struct tap_data_list* next;
|
||||
/** the data */
|
||||
struct tap_data* d;
|
||||
};
|
||||
|
||||
/** tap callback variables */
|
||||
struct tap_data {
|
||||
/** the fd */
|
||||
@@ -128,6 +137,10 @@ struct tap_data {
|
||||
uint8_t* frame;
|
||||
/** length of this frame */
|
||||
size_t len;
|
||||
/** back pointer to the tap_data_list entry;
|
||||
* used to NULL the forward pointer to this data
|
||||
* when this data is freed. */
|
||||
struct tap_data_list* data_list;
|
||||
};
|
||||
|
||||
/** list of sockets */
|
||||
@@ -156,8 +169,82 @@ struct tap_socket {
|
||||
char* ip;
|
||||
/** for a TLS socket, the tls context */
|
||||
SSL_CTX* sslctx;
|
||||
/** dumb way to deal with memory leaks:
|
||||
* tap_data was only freed on errors and not during exit leading to
|
||||
* false positives when testing for memory leaks. */
|
||||
struct tap_data_list* data_list;
|
||||
};
|
||||
|
||||
/** try to delete tail entries from the list if all of them have no data */
|
||||
static void tap_data_list_try_to_free_tail(struct tap_data_list* list)
|
||||
{
|
||||
struct tap_data_list* current = list;
|
||||
log_assert(!list->d);
|
||||
if(!list->next) /* we are the last, we can't remove ourselves */
|
||||
return;
|
||||
list = list->next;
|
||||
while(list) {
|
||||
if(list->d) /* a tail entry still has data; return */
|
||||
return;
|
||||
list = list->next;
|
||||
}
|
||||
/* keep the next */
|
||||
list = current->next;
|
||||
/* the tail will be removed; but not ourselves */
|
||||
current->next = NULL;
|
||||
while(list) {
|
||||
current = list;
|
||||
list = list->next;
|
||||
free(current);
|
||||
}
|
||||
}
|
||||
|
||||
/** delete the tap structure */
|
||||
static void tap_data_free(struct tap_data* data)
|
||||
{
|
||||
ub_event_del(data->ev);
|
||||
ub_event_free(data->ev);
|
||||
#ifdef HAVE_SSL
|
||||
SSL_free(data->ssl);
|
||||
#endif
|
||||
close(data->fd);
|
||||
free(data->id);
|
||||
free(data->frame);
|
||||
data->data_list->d = NULL;
|
||||
tap_data_list_try_to_free_tail(data->data_list);
|
||||
free(data);
|
||||
}
|
||||
|
||||
/** insert tap_data in the tap_data_list */
|
||||
static int tap_data_list_insert(struct tap_data_list** liststart,
|
||||
struct tap_data* d)
|
||||
{
|
||||
struct tap_data_list* entry = (struct tap_data_list*)
|
||||
malloc(sizeof(*entry));
|
||||
if(!entry)
|
||||
return 0;
|
||||
entry->next = *liststart;
|
||||
entry->d = d;
|
||||
d->data_list = entry;
|
||||
*liststart = entry;
|
||||
return 1;
|
||||
}
|
||||
|
||||
/** delete the tap_data_list and free any remaining tap_data */
|
||||
static void tap_data_list_delete(struct tap_data_list* list)
|
||||
{
|
||||
struct tap_data_list* e = list, *next;
|
||||
while(e) {
|
||||
next = e->next;
|
||||
if(e->d) {
|
||||
tap_data_free(e->d);
|
||||
e->d = NULL;
|
||||
}
|
||||
free(e);
|
||||
e = next;
|
||||
}
|
||||
}
|
||||
|
||||
/** del the tap event */
|
||||
static void tap_socket_delev(struct tap_socket* s)
|
||||
{
|
||||
@@ -184,6 +271,7 @@ static void tap_socket_delete(struct tap_socket* s)
|
||||
#ifdef HAVE_SSL
|
||||
SSL_CTX_free(s->sslctx);
|
||||
#endif
|
||||
tap_data_list_delete(s->data_list);
|
||||
ub_event_free(s->ev);
|
||||
free(s->socketpath);
|
||||
free(s->ip);
|
||||
@@ -708,7 +796,7 @@ static ssize_t ssl_read_bytes(struct tap_data* data, void* buf, size_t len)
|
||||
(data->id?data->id:""));
|
||||
return 0;
|
||||
}
|
||||
log_crypto_err("could not SSL_read");
|
||||
log_crypto_err_io("could not SSL_read", want);
|
||||
if(verbosity) log_info("dnstap client stream closed from %s",
|
||||
(data->id?data->id:""));
|
||||
return 0;
|
||||
@@ -728,20 +816,6 @@ static ssize_t tap_receive(struct tap_data* data, void* buf, size_t len)
|
||||
return receive_bytes(data, data->fd, buf, len);
|
||||
}
|
||||
|
||||
/** delete the tap structure */
|
||||
static void tap_data_free(struct tap_data* data)
|
||||
{
|
||||
ub_event_del(data->ev);
|
||||
ub_event_free(data->ev);
|
||||
#ifdef HAVE_SSL
|
||||
SSL_free(data->ssl);
|
||||
#endif
|
||||
close(data->fd);
|
||||
free(data->id);
|
||||
free(data->frame);
|
||||
free(data);
|
||||
}
|
||||
|
||||
/** reply with ACCEPT control frame to bidirectional client,
|
||||
* returns 0 on error */
|
||||
static int reply_with_accept(struct tap_data* data)
|
||||
@@ -760,10 +834,11 @@ static int reply_with_accept(struct tap_data* data)
|
||||
fd_set_block(data->fd);
|
||||
if(data->ssl) {
|
||||
if((r=SSL_write(data->ssl, acceptframe, len)) <= 0) {
|
||||
if(SSL_get_error(data->ssl, r) == SSL_ERROR_ZERO_RETURN)
|
||||
int r2;
|
||||
if((r2=SSL_get_error(data->ssl, r)) == SSL_ERROR_ZERO_RETURN)
|
||||
log_err("SSL_write, peer closed connection");
|
||||
else
|
||||
log_err("could not SSL_write");
|
||||
log_crypto_err_io("could not SSL_write", r2);
|
||||
fd_set_nonblock(data->fd);
|
||||
free(acceptframe);
|
||||
return 0;
|
||||
@@ -805,10 +880,11 @@ static int reply_with_finish(struct tap_data* data)
|
||||
if(data->ssl) {
|
||||
int r;
|
||||
if((r=SSL_write(data->ssl, finishframe, len)) <= 0) {
|
||||
if(SSL_get_error(data->ssl, r) == SSL_ERROR_ZERO_RETURN)
|
||||
int r2;
|
||||
if((r2=SSL_get_error(data->ssl, r)) == SSL_ERROR_ZERO_RETURN)
|
||||
log_err("SSL_write, peer closed connection");
|
||||
else
|
||||
log_err("could not SSL_write");
|
||||
log_crypto_err_io("could not SSL_write", r2);
|
||||
fd_set_nonblock(data->fd);
|
||||
free(finishframe);
|
||||
return 0;
|
||||
@@ -840,7 +916,11 @@ static int tap_check_peer(struct tap_data* data)
|
||||
if((SSL_get_verify_mode(data->ssl)&SSL_VERIFY_PEER)) {
|
||||
/* verification */
|
||||
if(SSL_get_verify_result(data->ssl) == X509_V_OK) {
|
||||
#ifdef HAVE_SSL_GET1_PEER_CERTIFICATE
|
||||
X509* x = SSL_get1_peer_certificate(data->ssl);
|
||||
#else
|
||||
X509* x = SSL_get_peer_certificate(data->ssl);
|
||||
#endif
|
||||
if(!x) {
|
||||
if(verbosity) log_info("SSL connection %s"
|
||||
" failed no certificate", data->id);
|
||||
@@ -862,7 +942,11 @@ static int tap_check_peer(struct tap_data* data)
|
||||
#endif
|
||||
X509_free(x);
|
||||
} else {
|
||||
#ifdef HAVE_SSL_GET1_PEER_CERTIFICATE
|
||||
X509* x = SSL_get1_peer_certificate(data->ssl);
|
||||
#else
|
||||
X509* x = SSL_get_peer_certificate(data->ssl);
|
||||
#endif
|
||||
if(x) {
|
||||
if(verbosity)
|
||||
log_cert(VERB_ALGO, "peer certificate", x);
|
||||
@@ -1044,7 +1128,6 @@ void dtio_tap_callback(int ATTR_UNUSED(fd), short ATTR_UNUSED(bits), void* arg)
|
||||
data->len = 0;
|
||||
data->len_done = 0;
|
||||
data->data_done = 0;
|
||||
|
||||
}
|
||||
|
||||
/** callback for main listening file descriptor */
|
||||
@@ -1127,6 +1210,8 @@ void dtio_mainfdcallback(int fd, short ATTR_UNUSED(bits), void* arg)
|
||||
&dtio_tap_callback, data);
|
||||
if(!data->ev) fatal_exit("could not ub_event_new");
|
||||
if(ub_event_add(data->ev, NULL) != 0) fatal_exit("could not ub_event_add");
|
||||
if(!tap_data_list_insert(&tap_sock->data_list, data))
|
||||
fatal_exit("could not tap_data_list_insert");
|
||||
}
|
||||
|
||||
/** setup local accept sockets */
|
||||
@@ -1241,6 +1326,79 @@ setup_and_run(struct config_strlist_head* local_list,
|
||||
free(maindata);
|
||||
}
|
||||
|
||||
/* internal unit tests */
|
||||
static int internal_unittest()
|
||||
{
|
||||
/* unit test tap_data_list_try_to_free_tail() */
|
||||
#define unit_tap_datas_max 5
|
||||
struct tap_data* datas[unit_tap_datas_max];
|
||||
struct tap_data_list* list;
|
||||
struct tap_socket* socket = calloc(1, sizeof(*socket));
|
||||
size_t i = 0;
|
||||
log_assert(socket);
|
||||
log_assert(unit_tap_datas_max>2); /* needed for the test */
|
||||
for(i=0; i<unit_tap_datas_max; i++) {
|
||||
datas[i] = calloc(1, sizeof(struct tap_data));
|
||||
log_assert(datas[i]);
|
||||
log_assert(tap_data_list_insert(&socket->data_list, datas[i]));
|
||||
}
|
||||
/* sanity base check */
|
||||
list = socket->data_list;
|
||||
for(i=0; list; i++) list = list->next;
|
||||
log_assert(i==unit_tap_datas_max);
|
||||
|
||||
/* Free the last data, tail cannot be erased */
|
||||
list = socket->data_list;
|
||||
while(list->next) list = list->next;
|
||||
free(list->d);
|
||||
list->d = NULL;
|
||||
tap_data_list_try_to_free_tail(list);
|
||||
list = socket->data_list;
|
||||
for(i=0; list; i++) list = list->next;
|
||||
log_assert(i==unit_tap_datas_max);
|
||||
|
||||
/* Free the third to last data, tail cannot be erased */
|
||||
list = socket->data_list;
|
||||
for(i=0; i<unit_tap_datas_max-3; i++) list = list->next;
|
||||
free(list->d);
|
||||
list->d = NULL;
|
||||
tap_data_list_try_to_free_tail(list);
|
||||
list = socket->data_list;
|
||||
for(i=0; list; i++) list = list->next;
|
||||
log_assert(i==unit_tap_datas_max);
|
||||
|
||||
/* Free the second to last data, try to remove tail from the third
|
||||
* again, tail (last 2) should be removed */
|
||||
list = socket->data_list;
|
||||
for(i=0; i<unit_tap_datas_max-2; i++) list = list->next;
|
||||
free(list->d);
|
||||
list->d = NULL;
|
||||
list = socket->data_list;
|
||||
while(list->d) list = list->next;
|
||||
tap_data_list_try_to_free_tail(list);
|
||||
list = socket->data_list;
|
||||
for(i=0; list; i++) list = list->next;
|
||||
log_assert(i==unit_tap_datas_max-2);
|
||||
|
||||
/* Free all the remaining data, try to remove tail from the start,
|
||||
* only the start should remain */
|
||||
list = socket->data_list;
|
||||
while(list) {
|
||||
free(list->d);
|
||||
list->d = NULL;
|
||||
list = list->next;
|
||||
}
|
||||
tap_data_list_try_to_free_tail(socket->data_list);
|
||||
list = socket->data_list;
|
||||
for(i=0; list; i++) list = list->next;
|
||||
log_assert(i==1);
|
||||
|
||||
/* clean up */
|
||||
tap_data_list_delete(socket->data_list);
|
||||
free(socket);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/** getopt global, in case header files fail to declare it. */
|
||||
extern int optind;
|
||||
/** getopt global, in case header files fail to declare it. */
|
||||
@@ -1291,7 +1449,7 @@ int main(int argc, char** argv)
|
||||
#endif
|
||||
|
||||
/* command line options */
|
||||
while( (c=getopt(argc, argv, "hls:t:u:vx:y:z:")) != -1) {
|
||||
while( (c=getopt(argc, argv, "hcls:t:u:vx:y:z:")) != -1) {
|
||||
switch(c) {
|
||||
case 'u':
|
||||
if(!cfg_strlist_append(&local_list,
|
||||
@@ -1327,6 +1485,12 @@ int main(int argc, char** argv)
|
||||
case 'v':
|
||||
verbosity++;
|
||||
break;
|
||||
case 'c':
|
||||
#ifndef UNBOUND_DEBUG
|
||||
fatal_exit("-c option needs compilation with "
|
||||
"--enable-debug");
|
||||
#endif
|
||||
return internal_unittest();
|
||||
case 'h':
|
||||
case '?':
|
||||
default:
|
||||
|
||||
+667
-1
@@ -1,3 +1,669 @@
|
||||
19 July 2024: Wouter
|
||||
- Add dnstap-sample-rate that logs only 1/N messages, for high volume
|
||||
server environments. Thanks Dan Luther.
|
||||
- Fix dnstap wakeup, a running wakeup timer is left to expire and not
|
||||
increased, a timer is started when the dtio thread is sleeping,
|
||||
the timer set disabled when the dtio thread goes to sleep, and
|
||||
after sleep the thread checks to see if there are messages to log
|
||||
immediately.
|
||||
|
||||
16 July 2024: Wouter
|
||||
- For #1103: Fix to drop mesh state reference for the http2 stream
|
||||
associated with the reply, not the currently active stream. And
|
||||
it does not remove it twice on a mesh_send_reply call. The reply
|
||||
h2_stream is NULL when not in use, for more initialisation.
|
||||
|
||||
15 July 2024: Wouter
|
||||
- For #1103: fix to also drop mesh state reference when the discard
|
||||
limit is reached, when there is an error making a new recursion
|
||||
state and when the connection is dropped with is_drop.
|
||||
|
||||
12 July 2024: Yorgos
|
||||
- Add RPZ tag tests in acl_interface.tdir.
|
||||
- For #1102: clearer text for using interface-* options for the
|
||||
loopback interface.
|
||||
|
||||
12 July 2024: Wouter
|
||||
- Fix #1103: unbound 1.20.0 segmentation fault with nghttp2.
|
||||
- For #1103: fix to also drop mesh state reference when a h2 reply is
|
||||
dropped.
|
||||
|
||||
10 July 2024: Wouter
|
||||
- For #773: In contrib/unbound.service.in set unbound to start after
|
||||
network-online.target. Also for contrib/unbound_portable.service.in.
|
||||
|
||||
9 July 2024: Yorgos
|
||||
- Update list of known EDE codes.
|
||||
|
||||
8 July 2024: Wouter
|
||||
- Fix that validation reason failure that uses string print uses
|
||||
separate buffer that is passed, from the scratch validation buffer.
|
||||
- Fixup algo_needs_reason string buffer length.
|
||||
- Fix shadowed error string variable in validator dnskey handling.
|
||||
|
||||
5 July 2024: Yorgos
|
||||
- Don't check for message TTL changes if the RRsets remain the same.
|
||||
|
||||
5 July 2024: Wouter
|
||||
- Fix for neater printout for error for missing DS response.
|
||||
- Fix neater printout.
|
||||
- Fix #1099: Unbound core dump on SIGSEGV.
|
||||
- Fix for #1099: Fix to check for deleted RRset when the contents
|
||||
is updated and fetched after it is stored, and also check for a
|
||||
changed RRset.
|
||||
|
||||
4 July 2024: Wouter
|
||||
- Fix to print details about the failure to lookup a DNSKEY record
|
||||
when validation fails due to the missing DNSKEY. Also for key prime
|
||||
and DS lookups.
|
||||
|
||||
3 July 2024: Yorgos
|
||||
- Fix for repeated use of a DNAME record: first overallocate and then
|
||||
move the exact size of the init value to avoid false positive heap
|
||||
overflow reads from address sanitizers.
|
||||
|
||||
3 July 2024: Wouter
|
||||
- Fix #144: Port ipset to BSD pf tables.
|
||||
- Add unit test skip files and bison and flex output to gitignore.
|
||||
- Fix to use modstack_init in zonemd unit test.
|
||||
- Fix to remove unneeded linebreak in fptr_wlist.c.
|
||||
- Fix compile warnings in fptr_wlist.c.
|
||||
|
||||
2 July 2024: Wouter
|
||||
- Fix to remove unused include from the readzone test program.
|
||||
- Fix unused variable warning in do_cache_remove.
|
||||
- Fix compile warning in worker pthread id printout.
|
||||
|
||||
17 June 2024: Wouter
|
||||
- Fix ip-ratelimit-cookie setting, it was not applied.
|
||||
|
||||
26 June 2024: Yorgos
|
||||
- Explicitly set the RD bit for the mesh query flags when prefetching.
|
||||
These queries have no waiting client but they need to be treated as
|
||||
recursive.
|
||||
|
||||
21 June 2024: Yorgos
|
||||
- Fix pkg-config availability check in dnstap/dnstap.m4 and
|
||||
systemd.m4.
|
||||
|
||||
19 June 2024: Yorgos
|
||||
- Fix #1092: Ubuntu 22.04 Jammy fails to compile unbound 1.20.0; by
|
||||
adding helpful text for the Python interpreter version and allowing
|
||||
the default pkg-config unavailability error message to be shown.
|
||||
|
||||
17 June 2024: Wouter
|
||||
- Fix #1091: Build fails with OpenSSL >= 3.0 built with
|
||||
OPENSSL_NO_DEPRECATED.
|
||||
|
||||
7 June 2024: Wouter
|
||||
- Add unit test for validation of repeated use of a DNAME record.
|
||||
|
||||
6 June 2024: Wouter
|
||||
- Fix memory leak in setup of dsa sig.
|
||||
- Fix typos for 'the the' in text.
|
||||
- Fix validation for repeated use of a DNAME record.
|
||||
|
||||
4 June 2024: Yorgos
|
||||
- Merge #1080: AddressSanitizer detection in tdir tests and memory leak
|
||||
fixes.
|
||||
- Fix memory leak when reload_keep_cache is used and num-threads
|
||||
changes.
|
||||
- Fix memory leak on exit for unbound-dnstap-socket; creates false
|
||||
negatives during testing.
|
||||
|
||||
3 June 2024: Wouter
|
||||
- Fix to squelch connection reset by peer errors from log. And fix
|
||||
that the tcp read errors are labeled as initial for the first calls.
|
||||
|
||||
30 May 2024: Wouter
|
||||
- Fix #1079: tags from tagged rpz zones are no longer honored after
|
||||
upgrade from 1.19.3 to 1.20.0.
|
||||
- Fix for #1079: fix RPZ taglist in iterator callback that no client
|
||||
info is like no taglist intersection.
|
||||
|
||||
29 May 2024: Wouter
|
||||
- Merge #1078: Only check old pid if no username.
|
||||
|
||||
27 May 2024: Wouter
|
||||
- Fix to enable that SERVFAIL is cached, for a short period, for more
|
||||
cases. In the cases where limits are exceeded.
|
||||
- Fix spelling of tcp-idle-timeout docs, from Michael Tokarev.
|
||||
|
||||
27 May 2024: Yorgos
|
||||
- Fix unused variable warning on compilation with no thread support.
|
||||
- unbound-control-setup: check openssl availability before doing
|
||||
anything, patch from Michael Tokarev.
|
||||
- Update patch to remove 'command' shell builtin and update error
|
||||
text.
|
||||
|
||||
24 May 2024: Wouter
|
||||
- Fix #1064: Unbound 1.20 Cachedb broken?
|
||||
|
||||
24 May 2024: Yorgos
|
||||
- Fix #1059: Intermittent DNS blocking failure with local-zone and
|
||||
always_nxdomain. Addition of local_zones dynamically via
|
||||
unbound-control was not finding the zone's parent correctly.
|
||||
|
||||
21 May 2024: Wouter
|
||||
- Merge #1073: fix null pointer dereference issue in function
|
||||
ub_ctx_set_fwd.
|
||||
- Fix to print a parse error when config is read with no name for
|
||||
a forward-zone, stub-zone or view.
|
||||
- Fix for parse end of forward-zone, stub-zone and view.
|
||||
- Fix for #1064: Fix that cachedb expired messages are considered
|
||||
insecure, and thus can be served to clients when dnssec is enabled.
|
||||
|
||||
17 May 2024: Yorgos
|
||||
- Merge #1069: Fix unbound-control stdin commands for multi-process
|
||||
Unbounds.
|
||||
- Fix unbound-control commands that read stdin in multi-process
|
||||
operation (local_zones_remove, local_zones, local_datas_remove,
|
||||
local_datas, view_local_datas_remove, view_local_datas). They will
|
||||
be properly distributed to all processes. dump_cache and load_cache
|
||||
are no longer supported in multi-process operation.
|
||||
- Remove testdata/remote-threaded.tdir. testdata/09-unbound-control.tdir
|
||||
now checks both single and multi process/thread operation.
|
||||
|
||||
16 May 2024: Yorgos
|
||||
- Merge #1070: Fix rtt assignement for low values of
|
||||
infra-cache-max-rtt.
|
||||
|
||||
16 May 2024: Wouter
|
||||
- Fix #1071: [FR] Clear both in-memory and cachedb module cache with
|
||||
`unbound-control flush*` commands.
|
||||
|
||||
15 May 2024: Yorgos
|
||||
- Add missing common functions to tdir tests.
|
||||
|
||||
10 May 2024: Wouter
|
||||
- Fix when the mesh jostle is exceeded that nameserver targets are
|
||||
marked as resolved, so that the lookup is not stuck on the
|
||||
requestlist.
|
||||
|
||||
8 May 2024: Wouter
|
||||
- Fix to squelch udp connect errors in the log at low verbosity about
|
||||
invalid argument for IPv6 link local addresses.
|
||||
|
||||
7 May 2024: Wouter
|
||||
- Merge #1062: Fix potential overflow bug while parsing port in
|
||||
function cfg_mark_ports.
|
||||
- Fix for #1062: declaration before statement, avoid print of null,
|
||||
and redundant check for array size.
|
||||
|
||||
1 May 2024: Wouter
|
||||
- Fix for the DNSBomb vulnerability CVE-2024-33655. Thanks to Xiang Li
|
||||
from the Network and Information Security Lab of Tsinghua University
|
||||
for reporting it.
|
||||
- Set version number to 1.20.0 for release. This became the release
|
||||
on 8 may 2024, the repository continues with version 1.20.1.
|
||||
|
||||
29 April 2024: Yorgos
|
||||
- Cleanup unnecessary strdup calls for EDE strings.
|
||||
|
||||
29 April 2024: Wouter
|
||||
- Fix doxygen comment for errinf_to_str_bogus.
|
||||
|
||||
26 April 2024: Wouter
|
||||
- Fix cachedb with serve-expired-client-timeout disabled. The edns
|
||||
subnet module deletes global cache and cachedb cache when it
|
||||
stores a result, and serve-expired is enabled, so that the global
|
||||
reply, that is older than the ecs reply, does not return after
|
||||
the ecs reply expires.
|
||||
- Add unit tests for cachedb and subnet cache expired data.
|
||||
- Man page entry for unbound-checkconf -q.
|
||||
|
||||
26 April 2024: Yorgos
|
||||
- Fix #876: [FR] can unbound-checkconf be silenced when configuration
|
||||
is valid?
|
||||
|
||||
25 April 2024: Wouter
|
||||
- Fix configure flto check error, by finding grep for it.
|
||||
- Merge #1041: Stub and Forward unshare. This has one structure
|
||||
for them and fixes #1038: fatal error: Could not initialize
|
||||
thread / error: reading root hints.
|
||||
- Fix to disable fragmentation on systems with IP_DONTFRAG,
|
||||
with a nonzero value for the socket option argument.
|
||||
- Fix doc unit test for out of directory build.
|
||||
|
||||
24 April 2024: Wouter
|
||||
- Fix ci workflow for macos for moved install locations.
|
||||
|
||||
23 April 2024: Yorgos
|
||||
- Merge #1053: Remove child delegations from cache when grandchild
|
||||
delegations are returned from parent.
|
||||
|
||||
22 April 2024: Wouter
|
||||
- Add checklock feature verbose_locking to trace locks and unlocks.
|
||||
- Fix edns subnet to sort rrset references when storing messages
|
||||
in the cache. This fixes a race condition in the rrset locks.
|
||||
|
||||
15 April 2024: Wouter
|
||||
- Fix #1048: Update ax_pkg_swig.m4 and ax_pthread.m4.
|
||||
- Fix configure, autoconf for #1048.
|
||||
|
||||
15 April 2024: Yorgos
|
||||
- Merge #1049 from Petr Menšík: Py_NoSiteFlag is not needed since
|
||||
Python 3.8
|
||||
|
||||
12 April 2024: Wouter
|
||||
- Fix cachedb for serve-expired with serve-expired-client-timeout.
|
||||
- Fixup unit test for cachedb server expired client timeout with
|
||||
a check if response if from upstream or from cachedb.
|
||||
- Fixup cachedb to not refetch when serve-expired-client-timeout is
|
||||
used.
|
||||
|
||||
10 April 2024: Wouter
|
||||
- Implement cachedb-check-when-serve-expired: yes option, default
|
||||
is enabled. When serve expired is enabled with cachedb, it first
|
||||
checks cachedb before serving the expired response.
|
||||
- Fixup compile without cachedb.
|
||||
- Add test for cachedb serve expired.
|
||||
- Extended test for cachedb serve expired.
|
||||
- Fix makefile dependencies for fake_event.c.
|
||||
- Fix cachedb for serve-expired with serve-expired-reply-ttl.
|
||||
- Fix to not reply serve expired unless enabled for cachedb.
|
||||
|
||||
9 April 2024: Yorgos
|
||||
- Merge #1043 from xiaoxiaoafeifei: Add loongarch support; updates
|
||||
config.guess(2024-01-01) and config.sub(2024-01-01), verified
|
||||
with upstream.
|
||||
|
||||
8 April 2024: Yorgos
|
||||
- Fix #595: unbound-anchor cannot deal with full disk; it will now
|
||||
first write out to a temp file before replacing the original one,
|
||||
like Unbound already does for auto-trust-anchor-file.
|
||||
|
||||
5 April 2024: Wouter
|
||||
- Fix comment syntax for view function views_find_view.
|
||||
|
||||
5 April 2024: Yorgos
|
||||
- Merge #1027: Introduce 'cache-min-negative-ttl' option.
|
||||
|
||||
3 April 2024: Wouter
|
||||
- Fix #1040: fix heap-buffer-overflow issue in function cfg_mark_ports
|
||||
of file util/config_file.c.
|
||||
- For #1040: adjust error text and disallow negative ports in other
|
||||
parts of cfg_mark_ports.
|
||||
|
||||
3 April 2024: Yorgos
|
||||
- Fix #1035: Potential Bug while parsing port from the "stub-host"
|
||||
string; also affected forward-zones and remote-control host
|
||||
directives.
|
||||
- Fix #369: dnstap showing extra responses; for client responses
|
||||
right from the cache when replying with expired data or
|
||||
prefetching.
|
||||
|
||||
28 March 2024: Wouter
|
||||
- Fix #1034: DoT forward-zone via unbound-control.
|
||||
- Fix for crypto related failures to have a better error string.
|
||||
|
||||
27 March 2024: Wouter
|
||||
- Fix name of unit test for subnet cache response.
|
||||
- Fix #1032: The size of subnet_msg_cache calculation mistake cause
|
||||
memory usage increased beyond expectations.
|
||||
- Fix for #1032, add safeguard to make table space positive.
|
||||
- Fix comment in lruhash space function.
|
||||
- Fix to add unit test for lruhash space that exercises the routines.
|
||||
- Fix that when the server truncates the pidfile, it does not follow
|
||||
symbolic links.
|
||||
- Fix that the server does not chown the pidfile.
|
||||
|
||||
25 March 2024: Yorgos
|
||||
- Merge #831 from Pierre4012: Improve Windows NSIS installer
|
||||
script (setup.nsi).
|
||||
- For #831: Format text, use exclamation icon and explicit label
|
||||
names.
|
||||
|
||||
19 March 2024: Wouter
|
||||
- Fix rpz so that rpz CNAME can apply after rpz CNAME. And fix that
|
||||
clientip and nsip can give a CNAME.
|
||||
- Fix localdata and rpz localdata to match CNAME only if no direct
|
||||
type match is available.
|
||||
|
||||
18 March 2024: Wouter
|
||||
- Fix that rpz CNAME content is limited to the max number of cnames.
|
||||
- Fix rpz, it follows iterator CNAMEs for nsip and nsdname and sets
|
||||
the reply query_info values, that is better for debug logging.
|
||||
- Fix rpz that copies the cname override completely to the temp
|
||||
region, so there are no references to the rpz region.
|
||||
- Add rpz unit test for nsip action override.
|
||||
- Fix rpz for qtype CNAME after nameserver trigger.
|
||||
|
||||
15 March 2024: Yorgos
|
||||
- Merge #1030: Persist the openssl and expat directories for repeated
|
||||
Windows builds.
|
||||
|
||||
15 March 2024: Wouter
|
||||
- Fix that addrinfo is not kept around but copied and freed, so that
|
||||
log-destaddr uses a copy of the information, much like NSD does.
|
||||
|
||||
13 March 2024: Wouter
|
||||
- Fix #1029: rpz trigger clientip and action rpz-passthru not working
|
||||
as expected.
|
||||
- Fix rpz that the rpz override is taken in case of clientip triggers.
|
||||
Fix that the clientip passthru action is logged. Fix that the
|
||||
clientip localdata action is logged. Fix rpz override action cname
|
||||
for the clientip trigger.
|
||||
- Fix to unify codepath for local alias for rpz cname action override.
|
||||
- Fix rpz for cname override action after nsdname and nsip triggers.
|
||||
|
||||
12 March 2024: Yorgos
|
||||
- Merge #1028: Clearer documentation for tcp-idle-timeout and
|
||||
edns-tcp-keepalive-timeout.
|
||||
|
||||
11 March 2024: Wouter
|
||||
- Fix #1021 Inconsistent Behavior with Changing rpz-cname-override
|
||||
and doing a unbound-control reload.
|
||||
|
||||
8 March 2024: Wouter
|
||||
- Fix unbound-control-setup.cmd to use 3072 bits so that certificates
|
||||
are long enough for newer OpenSSL versions. This fix is included
|
||||
in 1.19.3rc2.
|
||||
- Fix TTL of synthesized CNAME when a DNAME is used from cache. This
|
||||
fix is included in 1.19.3rc2.
|
||||
- Remove unused portion from iter_dname_ttl unit test.
|
||||
- Fix validator classification of qtype DNAME for positive and
|
||||
redirection answers, and fix validator signature routine for dealing
|
||||
with the synthesized CNAME for a DNAME without previously
|
||||
encountering it and also for when the qtype is DNAME.
|
||||
- Fix qname minimisation for reply with a DNAME for qtype CNAME that
|
||||
answers it.
|
||||
- Fix doc test so it ignores but outputs unsupported doxygen options.
|
||||
- Fix unbound-control-setup.cmd to have CA v3 basicConstraints,
|
||||
like unbound-control-setup.sh has. This fix is included in 1.19.3rc2.
|
||||
|
||||
8 March 2024: Yorgos
|
||||
- Update doc/unbound.doxygen with 'doxygen -u'. Fixes option
|
||||
deprecation warnings and updates with newer defaults.
|
||||
|
||||
7 March 2024: Wouter
|
||||
- Version set to 1.19.3 for release. After 1.19.2 point release with
|
||||
security fix for CVE-2024-1931, Denial of service when trimming
|
||||
EDE text on positive replies. The code repo includes the fix and
|
||||
is for version 1.19.3. The code repo continues for version 1.19.4,
|
||||
but 1.19.3 includes the fixes in 1.19.3rc2 as well.
|
||||
|
||||
5 March 2024: Wouter
|
||||
- Fix for #1022: Fix ede prohibited in access control refused answers.
|
||||
|
||||
4 March 2024: Wouter
|
||||
- Fix edns subnet replies for scope zero answers to not get stored
|
||||
in the global cache, and in cachedb, when the upstream replies
|
||||
without an EDNS record.
|
||||
|
||||
28 February 2024: Wouter
|
||||
- Move github workflows to use checkoutv4.
|
||||
|
||||
23 February 2024: Yorgos
|
||||
- Document the suspend argument for process_ds_response().
|
||||
|
||||
22 February 2024: Wouter
|
||||
- Fix trim of EDE text from large udp responses from spinning cpu.
|
||||
|
||||
20 February 2024: Yorgos
|
||||
- Merge #1010: Mention REFUSED has the TC bit set with unmatched
|
||||
allow_cookie acl in the manpage. It also fixes the code to match the
|
||||
documentation about clients with a valid cookie that bypass the
|
||||
ratelimit regardless of the allow_cookie acl.
|
||||
|
||||
13 February 2024: Wouter
|
||||
- Fix CVE-2023-50387, DNSSEC verification complexity can be exploited
|
||||
to exhaust CPU resources and stall DNS resolvers.
|
||||
- Fix CVE-2023-50868, NSEC3 closest encloser proof can exhaust CPU.
|
||||
- These fixes are part of the 1.19.1 release, that is a security
|
||||
point release on 1.19.0, the code repository continues with these
|
||||
fixes, with version number 1.19.2.
|
||||
|
||||
8 February 2024: Wouter
|
||||
- Fix documentation for access-control in the unbound.conf man page.
|
||||
|
||||
7 February 2024: Yorgos
|
||||
- Fix #1006: Can't find protobuf-c package since #999.
|
||||
|
||||
30 January 2024: Wouter
|
||||
- Merge #999: Search for protobuf-c with pkg-config.
|
||||
|
||||
23 January 2024: Yorgos
|
||||
- Update message TTL when using cached RRSETs. It could result in
|
||||
non-expired messages with expired RRSETs (non-usable messages by
|
||||
Unbound).
|
||||
|
||||
22 January 2024: Yorgos
|
||||
- Update error printout for duplicate trust anchors to include the
|
||||
trust anchor name (relates to #920).
|
||||
|
||||
22 January 2024: Wouter
|
||||
- Fix for #997: Print details for SSL certificate failure.
|
||||
|
||||
17 January 2024: Wouter
|
||||
- Update workflow for ports to use newer openssl on windows compile.
|
||||
- Fix warning for windres on resource files due to redefinition.
|
||||
|
||||
16 January 2024: Wouter
|
||||
- Fix to link with libssp for libcrypto and getaddrinfo check for
|
||||
only header. Also update crosscompile to remove ssp for 32bit.
|
||||
- Merge #993: Update b.root-servers.net also in example config file.
|
||||
|
||||
15 January 2024: Wouter
|
||||
- Fix to link with -lcrypt32 for OpenSSL 3.2.0 on Windows.
|
||||
|
||||
9 January 2024: Wouter
|
||||
- Merge #988: Fix NLnetLabs#981: dump_cache truncates large records.
|
||||
|
||||
5 January 2024: Wouter
|
||||
- Merge #987: skip edns frag retry if advertised udp payload size is
|
||||
not smaller.
|
||||
- Fix unit test for #987 change in udp1xxx retry packet send.
|
||||
|
||||
4 January 2024: Wouter
|
||||
- Remove unneeded newlines and improve indentation in remote control
|
||||
code.
|
||||
|
||||
3 January 2024: Wouter
|
||||
- Merge #980: DoH: reject non-h2 early. To fix #979: Improve errors
|
||||
for non-HTTP/2 DoH clients.
|
||||
- Merge #985: Add DoH and DoT to dnstap message.
|
||||
- Fix #983: Sha1 runtime insecure change was incomplete.
|
||||
|
||||
22 December 2023: Yorgos
|
||||
- Update example.conf with cookie options.
|
||||
|
||||
8 December 2023: Yorgos
|
||||
- Merge PR #973: Use the origin (DNAME) TTL for synthesized CNAMEs as
|
||||
per RFC 6672.
|
||||
|
||||
8 December 2023: Wouter
|
||||
- Fix root_zonemd unit test, it checks that the root ZONEMD verifies,
|
||||
now that the root has a valid ZONEMD.
|
||||
|
||||
7 December 2023: Wouter
|
||||
- Fix #974: doc: default number of outgoing ports without libevent.
|
||||
- Merge #975: Fixed some syntax errors in rpl files.
|
||||
|
||||
6 December 2023: Wouter
|
||||
- Fix to sync the tests script file common.sh.
|
||||
- iana portlist update.
|
||||
- Updated IPv4 and IPv6 address for b.root-servers.net in root hints.
|
||||
- Update test script file common.sh.
|
||||
- Fix tests to use new common.sh functions, wait_logfile and
|
||||
kill_from_pidfile.
|
||||
|
||||
5 December 2023: Wouter
|
||||
- Merge #971: fix 'WARNING: Message has 41 extra bytes at end'.
|
||||
- Fix #969: [FR] distinguish Do53, DoT and DoH in the logs.
|
||||
- Fix dnstap that assertion failed on logging other than UDP and TCP
|
||||
traffic. It lists it as TCP traffic.
|
||||
|
||||
27 November 2023: Yorgos
|
||||
- Merge #968: Replace the obsolescent fgrep with grep -F in tests.
|
||||
|
||||
27 November 2023: Wouter
|
||||
- Fix #964: config.h.in~ backup file in release tar balls.
|
||||
|
||||
24 November 2023: Yorgos
|
||||
- Use 127.0.0.1 explicitly in tests to avoid delays and errors on
|
||||
newer systems.
|
||||
|
||||
9 November 2023: Wouter
|
||||
- Fix unit test parse of origin syntax.
|
||||
|
||||
2 November 2023: Wouter
|
||||
- Set version number to 1.19.0.
|
||||
- Tag for 1.19.0rc1 release. It became 1.19.0 release on 8 nov 2023.
|
||||
The repository continues with 1.19.1.
|
||||
|
||||
1 November 2023: George
|
||||
- Mention flex and bison in README.md when building from repository
|
||||
source.
|
||||
|
||||
1 November 2023: Wouter
|
||||
- Fix SSL compile failure for definition in log_crypto_err_io_code_arg.
|
||||
- Fix SSL compile failure for other missing definitions in
|
||||
log_crypto_err_io_code_arg.
|
||||
- Fix compilation without openssl, remove unused function warning.
|
||||
|
||||
31 October 2023: George
|
||||
- Fix #941: dnscrypt doesn't work after upgrade to 1.18 with
|
||||
suggestion by dukeartem to also fix the udp_ancil with dnscrypt.
|
||||
|
||||
30 October 2023: George
|
||||
- Merge #930 from Stuart Henderson: add void to
|
||||
log_ident_revert_to_default declaration.
|
||||
|
||||
30 October 2023: Wouter
|
||||
- autoconf.
|
||||
|
||||
24 October 2023: George
|
||||
- Clearer configure text for missing protobuf-c development libraries.
|
||||
|
||||
20 October 2023: Wouter
|
||||
- Merge #951: Cachedb no store. The cachedb-no-store: yes option is
|
||||
used to stop cachedb from writing messages to the backend storage.
|
||||
It reads messages when data is available from the backend. The
|
||||
default is no.
|
||||
|
||||
19 October 2023: Wouter
|
||||
- Fix to print detailed errors when an SSL IO routine fails via
|
||||
SSL_get_error.
|
||||
|
||||
18 October 2023: George
|
||||
- Mailing list patches from Daniel Gröber for DNS64 fallback to plain
|
||||
AAAA when no A record exists for synthesis, and minor DNS64 code
|
||||
refactoring for better readability.
|
||||
- Fixes for the DNS64 patches.
|
||||
- Update the dns64_lookup.rpl test for the DNS64 fallback patch.
|
||||
- Merge #955 from buevsan: fix ipset wrong behavior.
|
||||
- Update testdata/ipset.tdir test for ipset fix.
|
||||
|
||||
17 October 2023: Wouter
|
||||
- Fix #954: Inconsistent RPZ handling for A record returned along with
|
||||
CNAME.
|
||||
|
||||
16 October 2023: George
|
||||
- Expose the script filename in the Python module environment 'mod_env'
|
||||
instead of the config_file structure which includes the linked list
|
||||
of scripts in a multi Python module setup; fixes #79.
|
||||
- Expose the configured listening and outgoing interfaces, if any, as
|
||||
a list of strings in the Python 'config_file' class instead of the
|
||||
current Swig object proxy; fixes #79.
|
||||
- For multi Python module setups, clean previously parsed module
|
||||
functions in __main__'s dictionary, if any, so that only current
|
||||
module functions are registered.
|
||||
|
||||
13 October 2023: George
|
||||
- Better fix for infinite loop when reading multiple lines of input on
|
||||
a broken remote control socket, by treating a zero byte line the
|
||||
same as transmission end. Addesses #947 and #948.
|
||||
|
||||
12 October 2023: Wouter
|
||||
- Merge #944: Disable EDNS DO.
|
||||
Disable the EDNS DO flag in upstream requests. This can be helpful
|
||||
for devices that cannot handle DNSSEC information. But it should not
|
||||
be enabled otherwise, because that would stop DNSSEC validation. The
|
||||
DNSSEC validation would not work for Unbound itself, and also not
|
||||
for downstream users. Default is no. The option
|
||||
is disable-edns-do: no
|
||||
|
||||
11 October 2023: George
|
||||
- Fix #850: [FR] Ability to use specific database in Redis, with new
|
||||
redis-logical-db configuration option.
|
||||
|
||||
11 October 2023: Wouter
|
||||
- Fix #949: "could not create control compt".
|
||||
- Fix that cachedb does not warn when serve-expired is disabled about
|
||||
use of serve-expired-reply-ttl and serve-expired-client-timeout.
|
||||
- Fix for #949: Fix pythonmod/ubmodule-tst.py for Python 3.x.
|
||||
|
||||
10 October 2023: George
|
||||
- Fix infinite loop when reading multiple lines of input on a broken
|
||||
remote control socket. Addesses #947 and #948.
|
||||
|
||||
9 October 2023: Wouter
|
||||
- Fix edns subnet so that queries with a source prefix of zero cause
|
||||
the recursor send no edns subnet option to the upstream.
|
||||
- Fix that printout of EDNS options shows the EDNS cookie option by
|
||||
name.
|
||||
|
||||
4 October 2023: Wouter
|
||||
- Fix #946: Forwarder returns servfail on upstream response noerror no
|
||||
data.
|
||||
|
||||
3 October 2023: George
|
||||
- Merge #881: Generalise the proxy protocol code.
|
||||
|
||||
2 October 2023: George
|
||||
- Fix misplaced comment.
|
||||
|
||||
22 September 2023: Wouter
|
||||
- Fix #942: 1.18.0 libunbound DNS regression when built without
|
||||
OpenSSL.
|
||||
|
||||
18 September 2023: Wouter
|
||||
- Fix rpz tcp-only action with rpz triggers nsdname and nsip.
|
||||
|
||||
15 September 2023: Wouter
|
||||
- Merge #936: Check for c99 with autoconf versions prior to 2.70.
|
||||
- Fix to remove two c99 notations.
|
||||
|
||||
14 September 2023: Wouter
|
||||
- Fix authority zone answers for obscured DNAMEs and delegations.
|
||||
|
||||
8 September 2023: Wouter
|
||||
- Fix send of udp retries when ENOBUFS is returned. It stops looping
|
||||
and also waits for the condition to go away. Reported by Florian
|
||||
Obser.
|
||||
|
||||
7 September 2023: Wouter
|
||||
- Fix to scrub resource records of type A and AAAA that have an
|
||||
inappropriate size. They are removed from responses.
|
||||
- Fix to move msgparse_rrset_remove_rr code to util/msgparse.c.
|
||||
- Fix to add EDE text when RRs have been removed due to length.
|
||||
- Fix to set ede match in unit test for rr length removal.
|
||||
- Fix to print EDE text in readable form in output logs.
|
||||
|
||||
6 September 2023: Wouter
|
||||
- Merge #931: Prevent warnings from -Wmissing-prototypes.
|
||||
|
||||
31 August 2023: Wouter
|
||||
- Fix autoconf 2.69 warnings in configure.
|
||||
- Fix #927: unbound 1.18.0 make test error. Fix make test without SHA1.
|
||||
|
||||
30 August 2023: Wouter
|
||||
- Fix for WKS call to getservbyname that creates allocation on exit
|
||||
in unit test by testing numbers first and testing from the services
|
||||
list later.
|
||||
|
||||
28 August 2023: Wouter
|
||||
- Fix for version generation race condition that ignored changes.
|
||||
|
||||
25 August 2023: Wouter
|
||||
- Fix compile error on NetBSD in util/netevent.h.
|
||||
|
||||
23 August 2023: Wouter
|
||||
- Tag for 1.18.0rc1 release. This became the 1.18.0 release on
|
||||
30 aug 2023, with the fix from 25 aug, fix compile on NetBSD
|
||||
included. The repository continues with version 1.18.1.
|
||||
|
||||
22 August 2023: Wouter
|
||||
- Set version number to 1.18.0.
|
||||
|
||||
@@ -4743,7 +5409,7 @@
|
||||
- Fix that with openssl 1.1 control-use-cert: no uses less cpu, by
|
||||
using no encryption over the unix socket.
|
||||
|
||||
22 Novenber 2016: Ralph
|
||||
22 November 2016: Ralph
|
||||
- Make access-control-tag-data RDATA absolute. This makes the RDATA
|
||||
origin consistent between local-data and access-control-tag-data.
|
||||
- Fix NSEC ENT wildcard check. Matching wildcard does not have to be a
|
||||
|
||||
+4
-5
@@ -19,11 +19,10 @@ The DNSTAP code has BSD license in dnstap/dnstap.c.
|
||||
* Make and install: ./configure; make; make install
|
||||
* --with-libevent=/path/to/libevent
|
||||
Can be set to either the system install or the build directory.
|
||||
--with-libevent=no (default) gives a builtin alternative
|
||||
implementation. libevent is useful when having many (thousands)
|
||||
of outgoing ports. This improves randomization and spoof
|
||||
resistance. For the default of 16 ports the builtin alternative
|
||||
works well and is a little faster.
|
||||
--with-libevent=no gives a builtin alternative implementation.
|
||||
Libevent is enabled by default, it is useful when having many
|
||||
(thousands) of outgoing ports. This improves randomization and spoof
|
||||
resistance. It also allows a higher number of outgoing queries.
|
||||
* --with-libexpat=/path/to/libexpat
|
||||
Can be set to the install directory of libexpat.
|
||||
* --without-pthreads
|
||||
|
||||
+57
-3
@@ -191,6 +191,21 @@ server:
|
||||
# are behind a slow satellite link, to eg. 1128.
|
||||
# unknown-server-time-limit: 376
|
||||
|
||||
# msec before recursion replies are dropped. The work item continues.
|
||||
# discard-timeout: 1900
|
||||
|
||||
# Max number of replies waiting for recursion per IP address.
|
||||
# wait-limit: 1000
|
||||
|
||||
# Max replies waiting for recursion for IP address with cookie.
|
||||
# wait-limit-cookie: 10000
|
||||
|
||||
# Apart from the default, the wait limit can be set for a netblock.
|
||||
# wait-limit-netblock: 192.0.2.0/24 50000
|
||||
|
||||
# Apart from the default, the wait limit with cookie can be adjusted.
|
||||
# wait-limit-cookie-netblock: 192.0.2.0/24 50000
|
||||
|
||||
# the amount of memory to use for the RRset cache.
|
||||
# plain value in bytes or you can append k, m or G. default is "4Mb".
|
||||
# rrset-cache-size: 4m
|
||||
@@ -211,6 +226,11 @@ server:
|
||||
# the time to live (TTL) value cap for negative responses in the cache
|
||||
# cache-max-negative-ttl: 3600
|
||||
|
||||
# the time to live (TTL) value lower bound, in seconds. Default 0.
|
||||
# For negative responses in the cache. If disabled, default,
|
||||
# cache-min-tll applies if configured.
|
||||
# cache-min-negative-ttl: 0
|
||||
|
||||
# the time to live (TTL) value for cached roundtrip times, lameness and
|
||||
# EDNS version information for hosts. In seconds.
|
||||
# infra-host-ttl: 900
|
||||
@@ -283,7 +303,8 @@ server:
|
||||
# Enable EDNS TCP keepalive option.
|
||||
# edns-tcp-keepalive: no
|
||||
|
||||
# Timeout for EDNS TCP keepalive, in msec.
|
||||
# Timeout for EDNS TCP keepalive, in msec. Overrides tcp-idle-timeout
|
||||
# if edns-tcp-keepalive is set.
|
||||
# edns-tcp-keepalive-timeout: 120000
|
||||
|
||||
# UDP queries that have waited in the socket buffer for a long time
|
||||
@@ -303,6 +324,7 @@ server:
|
||||
# Choose deny (drop message), refuse (polite error reply),
|
||||
# allow (recursive ok), allow_setrd (recursive ok, rd bit is forced on),
|
||||
# allow_snoop (recursive and nonrecursive ok)
|
||||
# allow_cookie (allow UDP with valid cookie or stateful transport)
|
||||
# deny_non_local (drop queries unless can be answered from local-data)
|
||||
# refuse_non_local (like deny_non_local but polite error reply).
|
||||
# access-control: 127.0.0.0/8 allow
|
||||
@@ -441,6 +463,9 @@ server:
|
||||
# filtering log-queries and log-replies from the log.
|
||||
# log-tag-queryreply: no
|
||||
|
||||
# log with destination address, port and type for log-replies.
|
||||
# log-destaddr: no
|
||||
|
||||
# log the local-zone actions, like local-zone type inform is enabled
|
||||
# also for the other local zone types.
|
||||
# log-local-actions: no
|
||||
@@ -683,6 +708,11 @@ server:
|
||||
# that set CD but cannot validate themselves.
|
||||
# ignore-cd-flag: no
|
||||
|
||||
# Disable the DO flag in outgoing requests. It is helpful for upstream
|
||||
# devices that cannot handle DNSSEC information. But do not enable it
|
||||
# otherwise, because it would stop DNSSEC validation.
|
||||
# disable-edns-do: no
|
||||
|
||||
# Serve expired responses from cache, with serve-expired-reply-ttl in
|
||||
# the response, and then attempt to fetch the data afresh.
|
||||
# serve-expired: no
|
||||
@@ -978,6 +1008,13 @@ server:
|
||||
# if 0(default) it is disabled, otherwise states qps allowed per ip address
|
||||
# ip-ratelimit: 0
|
||||
|
||||
# global query ratelimit for all ip addresses with a valid DNS Cookie.
|
||||
# feature is experimental.
|
||||
# if 0(default) it is disabled, otherwise states qps allowed per ip address
|
||||
# useful in combination with 'allow_cookie'.
|
||||
# If used, suggested to be higher than ip-ratelimit, tenfold.
|
||||
# ip-ratelimit-cookie: 0
|
||||
|
||||
# ip ratelimits are tracked in a cache, size in bytes of cache (or k,m).
|
||||
# ip-ratelimit-size: 4m
|
||||
# ip ratelimit cache slabs, reduces lock contention if equal to cpucount.
|
||||
@@ -999,6 +1036,14 @@ server:
|
||||
# the number of servers that will be used in the fast server selection.
|
||||
# fast-server-num: 3
|
||||
|
||||
# reply to requests containing DNS Cookies as specified in RFC 7873 and RFC 9018.
|
||||
# answer-cookie: no
|
||||
|
||||
# secret for DNS Cookie generation.
|
||||
# useful for anycast deployments.
|
||||
# example value "000102030405060708090a0b0c0d0e0f".
|
||||
# cookie-secret: <128 bit random hex string>
|
||||
|
||||
# Enable to attach Extended DNS Error codes (RFC8914) to responses.
|
||||
# ede: no
|
||||
|
||||
@@ -1145,7 +1190,7 @@ remote-control:
|
||||
# sources of notifies.
|
||||
# auth-zone:
|
||||
# name: "."
|
||||
# primary: 199.9.14.201 # b.root-servers.net
|
||||
# primary: 170.247.170.2 # b.root-servers.net
|
||||
# primary: 192.33.4.12 # c.root-servers.net
|
||||
# primary: 199.7.91.13 # d.root-servers.net
|
||||
# primary: 192.5.5.241 # f.root-servers.net
|
||||
@@ -1153,7 +1198,7 @@ remote-control:
|
||||
# primary: 193.0.14.129 # k.root-servers.net
|
||||
# primary: 192.0.47.132 # xfr.cjr.dns.icann.org
|
||||
# primary: 192.0.32.132 # xfr.lax.dns.icann.org
|
||||
# primary: 2001:500:200::b # b.root-servers.net
|
||||
# primary: 2801:1b8:10::b # b.root-servers.net
|
||||
# primary: 2001:500:2::c # c.root-servers.net
|
||||
# primary: 2001:500:2d::d # d.root-servers.net
|
||||
# primary: 2001:500:2f::f # f.root-servers.net
|
||||
@@ -1221,6 +1266,11 @@ remote-control:
|
||||
# backend: "testframe"
|
||||
# # secret seed string to calculate hashed keys
|
||||
# secret-seed: "default"
|
||||
# # if the backend should be read from, but not written to.
|
||||
# cachedb-no-store: no
|
||||
# # if the cachedb should be checked before a serve-expired response is
|
||||
# # given, when serve-expired is enabled.
|
||||
# cachedb-check-when-serve-expired: yes
|
||||
#
|
||||
# # For "redis" backend:
|
||||
# # (to enable, use --with-libhiredis to configure before compiling)
|
||||
@@ -1236,6 +1286,8 @@ remote-control:
|
||||
# redis-timeout: 100
|
||||
# # set timeout on redis records based on DNS response TTL
|
||||
# redis-expire-records: no
|
||||
# # redis logical database to use, 0 is the default database.
|
||||
# redis-logical-db: 0
|
||||
|
||||
# IPSet
|
||||
# Add specify domain into set via ipset.
|
||||
@@ -1277,6 +1329,8 @@ remote-control:
|
||||
# dnstap-identity: ""
|
||||
# # if "" it uses the package version.
|
||||
# dnstap-version: ""
|
||||
# # log only 1/N messages, if 0 it is disabled. default 0.
|
||||
# dnstap-sample-rate: 0
|
||||
# dnstap-log-resolver-query-messages: no
|
||||
# dnstap-log-resolver-response-messages: no
|
||||
# dnstap-log-client-query-messages: no
|
||||
|
||||
@@ -14,6 +14,7 @@ unbound\-checkconf
|
||||
.B unbound\-checkconf
|
||||
.RB [ \-h ]
|
||||
.RB [ \-f ]
|
||||
.RB [ \-q ]
|
||||
.RB [ \-o
|
||||
.IR option ]
|
||||
.RI [ cfgfile ]
|
||||
@@ -37,6 +38,9 @@ Print full pathname, with chroot applied to it. Use with the \-o option.
|
||||
If given, after checking the config file the value of this option is
|
||||
printed to stdout. For "" (disabled) options an empty line is printed.
|
||||
.TP
|
||||
.B \-q
|
||||
Make the operation quiet, suppress output on success.
|
||||
.TP
|
||||
.I cfgfile
|
||||
The config file to read with settings for Unbound. It is checked.
|
||||
If omitted, the config file at the default location is checked.
|
||||
|
||||
+22
-13
@@ -121,31 +121,38 @@ Remove local data RRs read from stdin of unbound\-control. Input is one name per
|
||||
line. For bulk removals.
|
||||
.TP
|
||||
.B dump_cache
|
||||
The contents of the cache is printed in a text format to stdout. You can
|
||||
redirect it to a file to store the cache in a file.
|
||||
The content of the cache is printed in a text format to stdout.
|
||||
You can redirect it to a file to store the cache in a file.
|
||||
Not supported in remote Unbounds in multi-process operation.
|
||||
.TP
|
||||
.B load_cache
|
||||
The contents of the cache is loaded from stdin. Uses the same format as
|
||||
dump_cache uses. Loading the cache with old, or wrong data can result
|
||||
in old or wrong data returned to clients. Loading data into the cache
|
||||
in this way is supported in order to aid with debugging.
|
||||
The content of the cache is loaded from stdin.
|
||||
Uses the same format as dump_cache uses.
|
||||
Loading the cache with old, or wrong data can result in old or wrong data
|
||||
returned to clients.
|
||||
Loading data into the cache in this way is supported in order to aid with
|
||||
debugging.
|
||||
Not supported in remote Unbounds in multi-process operation.
|
||||
.TP
|
||||
.B lookup \fIname
|
||||
Print to stdout the name servers that would be used to look up the
|
||||
name specified.
|
||||
.TP
|
||||
.B flush \fIname
|
||||
.B flush \fR[\fI+c\fR] \fIname
|
||||
Remove the name from the cache. Removes the types
|
||||
A, AAAA, NS, SOA, CNAME, DNAME, MX, PTR, SRV, NAPTR, SVCB and HTTPS.
|
||||
Because that is fast to do. Other record types can be removed using
|
||||
.B flush_type
|
||||
or
|
||||
.B flush_zone\fR.
|
||||
.IP
|
||||
The '+c' option removes the items also from the cachedb cache. If
|
||||
cachedb is in use.
|
||||
.TP
|
||||
.B flush_type \fIname\fR \fItype
|
||||
.B flush_type \fR[\fI+c\fR] \fIname\fR \fItype
|
||||
Remove the name, type information from the cache.
|
||||
.TP
|
||||
.B flush_zone \fIname
|
||||
.B flush_zone \fR[\fI+c\fR] \fIname
|
||||
Remove all information at or below the name from the cache.
|
||||
The rrsets and key entries are removed so that new lookups will be performed.
|
||||
This needs to walk and inspect the entire cache, and is a slow operation.
|
||||
@@ -153,10 +160,10 @@ The entries are set to expired in the implementation of this command (so,
|
||||
with serve\-expired enabled, it'll serve that information but schedule a
|
||||
prefetch for new information).
|
||||
.TP
|
||||
.B flush_bogus
|
||||
.B flush_bogus \fR[\fI+c\fR]
|
||||
Remove all bogus data from the cache.
|
||||
.TP
|
||||
.B flush_negative
|
||||
.B flush_negative \fR[\fI+c\fR]
|
||||
Remove all negative data from the cache. This is nxdomain answers,
|
||||
nodata answers and servfail answers. Also removes bad key entries
|
||||
(which could be due to failed lookups) from the dnssec key cache, and
|
||||
@@ -239,22 +246,24 @@ still be bogus, use \fBflush_zone\fR to remove it), does not affect the config f
|
||||
.B insecure_remove \fIzone
|
||||
Removes domain\-insecure for the given zone.
|
||||
.TP
|
||||
.B forward_add \fR[\fI+i\fR] \fIzone addr ...
|
||||
.B forward_add \fR[\fI+it\fR] \fIzone addr ...
|
||||
Add a new forward zone to running Unbound. With +i option also adds a
|
||||
\fIdomain\-insecure\fR for the zone (so it can resolve insecurely if you have
|
||||
a DNSSEC root trust anchor configured for other names).
|
||||
The addr can be IP4, IP6 or nameserver names, like \fIforward-zone\fR config
|
||||
in unbound.conf.
|
||||
The +t option sets it to use tls upstream, like \fIforward\-tls\-upstream\fR: yes.
|
||||
.TP
|
||||
.B forward_remove \fR[\fI+i\fR] \fIzone
|
||||
Remove a forward zone from running Unbound. The +i also removes a
|
||||
\fIdomain\-insecure\fR for the zone.
|
||||
.TP
|
||||
.B stub_add \fR[\fI+ip\fR] \fIzone addr ...
|
||||
.B stub_add \fR[\fI+ipt\fR] \fIzone addr ...
|
||||
Add a new stub zone to running Unbound. With +i option also adds a
|
||||
\fIdomain\-insecure\fR for the zone. With +p the stub zone is set to prime,
|
||||
without it it is set to notprime. The addr can be IP4, IP6 or nameserver
|
||||
names, like the \fIstub-zone\fR config in unbound.conf.
|
||||
The +t option sets it to use tls upstream, like \fIstub\-tls\-upstream\fR: yes.
|
||||
.TP
|
||||
.B stub_remove \fR[\fI+i\fR] \fIzone
|
||||
Remove a stub zone from running Unbound. The +i also removes a
|
||||
|
||||
+116
-24
@@ -302,6 +302,36 @@ Increase this if you are behind a slow satellite link, to eg. 1128.
|
||||
That would then avoid re\-querying every initial query because it times out.
|
||||
Default is 376 msec.
|
||||
.TP
|
||||
.B discard\-timeout: \fI<msec>
|
||||
The wait time in msec where recursion requests are dropped. This is
|
||||
to stop a large number of replies from accumulating. They receive
|
||||
no reply, the work item continues to recurse. It is nice to be a bit
|
||||
larger than serve\-expired\-client\-timeout if that is enabled.
|
||||
A value of 1900 msec is suggested. The value 0 disables it.
|
||||
Default 1900 msec.
|
||||
.TP
|
||||
.B wait\-limit: \fI<number>
|
||||
The number of replies that can wait for recursion, for an IP address.
|
||||
This makes a ratelimit per IP address of waiting replies for recursion.
|
||||
It stops very large amounts of queries waiting to be returned to one
|
||||
destination. The value 0 disables wait limits. Default is 1000.
|
||||
.TP
|
||||
.B wait\-limit\-cookie: \fI<number>
|
||||
The number of replies that can wait for recursion, for an IP address
|
||||
that sent the query with a valid DNS cookie. Since the cookie validates
|
||||
the client address, the limit can be higher. Default is 10000.
|
||||
.TP
|
||||
.B wait\-limit\-netblock: \fI<netblock> <number>
|
||||
The wait limit for the netblock. If not given the wait\-limit value is
|
||||
used. The most specific netblock is used to determine the limit. Useful for
|
||||
overriding the default for a specific, group or individual, server.
|
||||
The value -1 disables wait limits for the netblock.
|
||||
.TP
|
||||
.B wait\-limit\-cookie\-netblock: \fI<netblock> <number>
|
||||
The wait limit for the netblock, when the query has a DNS cookie.
|
||||
If not given, the wait\-limit\-cookie value is used.
|
||||
The value -1 disables wait limits for the netblock.
|
||||
.TP
|
||||
.B so\-rcvbuf: \fI<number>
|
||||
If not 0, then set the SO_RCVBUF socket option to get more buffer
|
||||
space on UDP port 53 incoming queries. So that short spikes on busy
|
||||
@@ -388,6 +418,15 @@ Time to live maximum for negative responses, these have a SOA in the
|
||||
authority section that is limited in time. Default is 3600.
|
||||
This applies to nxdomain and nodata answers.
|
||||
.TP
|
||||
.B cache\-min\-negative\-ttl: \fI<seconds>
|
||||
Time to live minimum for negative responses, these have a SOA in the
|
||||
authority section that is limited in time.
|
||||
Default is 0 (disabled).
|
||||
If this is disabled and \fBcache-min-ttl\fR is configured, it will take effect
|
||||
instead.
|
||||
In that case you can set this to 1 to honor the upstream TTL.
|
||||
This applies to nxdomain and nodata answers.
|
||||
.TP
|
||||
.B infra\-host\-ttl: \fI<seconds>
|
||||
Time to live for entries in the host cache. The host cache contains
|
||||
roundtrip timing, lameness and EDNS support information. Default is 900.
|
||||
@@ -472,6 +511,8 @@ configured value if the number of free buffers falls below 35% of the
|
||||
total number configured, and finally to 0 if the number of free buffers
|
||||
falls below 20% of the total number configured. A minimum timeout of
|
||||
200 milliseconds is observed regardless of the option value used.
|
||||
It will be overridden by \fBedns\-tcp\-keepalive\-timeout\fR if
|
||||
\fBedns\-tcp\-keepalive\fR is enabled.
|
||||
.TP
|
||||
.B tcp-reuse-timeout: \fI<msec>\fR
|
||||
The period Unbound will keep TCP persistent connections open to
|
||||
@@ -490,20 +531,11 @@ This option defaults to 3000 milliseconds.
|
||||
Enable or disable EDNS TCP Keepalive. Default is no.
|
||||
.TP
|
||||
.B edns-tcp-keepalive-timeout: \fI<msec>\fR
|
||||
The period Unbound will wait for a query on a TCP connection when
|
||||
EDNS TCP Keepalive is active. If this timeout expires Unbound closes
|
||||
the connection. If the client supports the EDNS TCP Keepalive option,
|
||||
Overrides \fBtcp\-idle\-timeout\fR when \fBedns\-tcp\-keepalive\fR is enabled.
|
||||
If the client supports the EDNS TCP Keepalive option,
|
||||
Unbound sends the timeout value to the client to encourage it to
|
||||
close the connection before the server times out.
|
||||
This option defaults to 120000 milliseconds.
|
||||
When the number of free incoming TCP buffers falls below 50% of
|
||||
the total number configured, the advertised timeout is progressively
|
||||
reduced to 1% of the configured value, then to 0.2% of the configured
|
||||
value if the number of free buffers falls below 35% of the total number
|
||||
configured, and finally to 0 if the number of free buffers falls below
|
||||
20% of the total number configured.
|
||||
A minimum actual timeout of 200 milliseconds is observed regardless of the
|
||||
advertised timeout.
|
||||
.TP
|
||||
.B sock\-queue\-timeout: \fI<sec>\fR
|
||||
UDP queries that have waited in the socket buffer for a long time can be
|
||||
@@ -699,6 +731,12 @@ When at the limit, further connections are accepted but closed immediately.
|
||||
This option is experimental at this time.
|
||||
.TP
|
||||
.B access\-control: \fI<IP netblock> <action>
|
||||
Specify treatment of incoming queries from their originating IP address.
|
||||
Queries can be allowed to have access to this server that gives DNS
|
||||
answers, or refused, with other actions possible. The IP address range
|
||||
can be specified as a netblock, it is possible to give the statement
|
||||
several times in order to specify the treatment of different netblocks.
|
||||
.IP
|
||||
The netblock is given as an IP4 or IP6 address with /size appended for a
|
||||
classless network block. The action can be \fIdeny\fR, \fIrefuse\fR,
|
||||
\fIallow\fR, \fIallow_setrd\fR, \fIallow_snoop\fR, \fIallow_cookie\fR,
|
||||
@@ -738,7 +776,7 @@ the cache contents (for malicious acts). However, nonrecursive queries can
|
||||
also be a valuable debugging tool (when you want to examine the cache
|
||||
contents). In that case use \fIallow_snoop\fR for your administration host.
|
||||
.IP
|
||||
The \fIallow_cookie\fR action allows access to UDP queries that contain a
|
||||
The \fIallow_cookie\fR action allows access only to UDP queries that contain a
|
||||
valid DNS Cookie as specified in RFC 7873 and RFC 9018, when the
|
||||
\fBanswer\-cookie\fR option is enabled.
|
||||
UDP queries containing only a DNS Client Cookie and no Server Cookie, or an
|
||||
@@ -747,12 +785,11 @@ generated DNS Cookie, allowing clients to retry with that DNS Cookie.
|
||||
The \fIallow_cookie\fR action will also accept requests over stateful
|
||||
transports, regardless of the presence of an DNS Cookie and regardless of the
|
||||
\fBanswer\-cookie\fR setting.
|
||||
If \fBip\-ratelimit\fR is used, clients with a valid DNS Cookie will bypass the
|
||||
ratelimit.
|
||||
If a ratelimit for such clients is still needed, \fBip\-ratelimit\-cookie\fR
|
||||
can be used instead.
|
||||
UDP queries without a DNS Cookie receive REFUSED responses with the TC flag set,
|
||||
that may trigger fall back to TCP for those clients.
|
||||
.IP
|
||||
By default only localhost is \fIallow\fRed, the rest is \fIrefuse\fRd.
|
||||
By default only localhost (the 127.0.0.0/8 IP netblock, not the loopback
|
||||
interface) is implicitly \fIallow\fRed, the rest is \fIrefuse\fRd.
|
||||
The default is \fIrefuse\fRd, because that is protocol\-friendly. The DNS
|
||||
protocol is not designed to handle dropped packets due to policy, and
|
||||
dropping may result in (possibly excessive) retried queries.
|
||||
@@ -788,8 +825,12 @@ Similar to \fBaccess\-control:\fR but for interfaces.
|
||||
.IP
|
||||
The action is the same as the ones defined under \fBaccess\-control:\fR.
|
||||
Interfaces are \fIrefuse\fRd by default.
|
||||
By default only localhost (the IP netblock, not the loopback interface) is
|
||||
\fIallow\fRed through the default \fBaccess\-control:\fR behavior.
|
||||
By default only localhost (the 127.0.0.0/8 IP netblock, not the loopback
|
||||
interface) is implicitly \fIallow\fRed through the default
|
||||
\fBaccess\-control:\fR behavior.
|
||||
This also means that any attempt to use the \fBinterface-*:\fR options for the
|
||||
loopback interface will not work as they will be overridden by the implicit
|
||||
default "\fBaccess\-control:\fR 127.0.0.0/8 allow" option.
|
||||
.IP
|
||||
Note that the interface needs to be already specified with \fBinterface:\fR
|
||||
and that any \fBaccess-control*:\fR setting overrides all \fBinterface-*:\fR
|
||||
@@ -913,6 +954,11 @@ Prints the word 'query' and 'reply' with log\-queries and log\-replies.
|
||||
This makes filtering logs easier. The default is off (for backwards
|
||||
compatibility).
|
||||
.TP
|
||||
.B log\-destaddr: \fI<yes or no>
|
||||
Prints the destination address, port and type in the log\-replies output.
|
||||
This disambiguates what type of traffic, eg. udp or tcp, and to what local
|
||||
port the traffic was sent to.
|
||||
.TP
|
||||
.B log\-local\-actions: \fI<yes or no>
|
||||
Print log lines to inform about local zone actions. These lines are like the
|
||||
local\-zone type inform prints out, but they are also printed for the other
|
||||
@@ -1302,6 +1348,20 @@ servers that set the CD flag but cannot validate DNSSEC themselves are
|
||||
the clients, and then Unbound provides them with DNSSEC protection.
|
||||
The default value is "no".
|
||||
.TP
|
||||
.B disable\-edns\-do: \fI<yes or no>
|
||||
Disable the EDNS DO flag in upstream requests.
|
||||
It breaks DNSSEC validation for Unbound's clients.
|
||||
This results in the upstream name servers to not include DNSSEC records in
|
||||
their replies and could be helpful for devices that cannot handle DNSSEC
|
||||
information.
|
||||
When the option is enabled, clients that set the DO flag receive no EDNS
|
||||
record in the response to indicate the lack of support to them.
|
||||
If this option is enabled but Unbound is already configured for DNSSEC
|
||||
validation (i.e., the validator module is enabled; default) this option is
|
||||
implicitly turned off with a warning as to not break DNSSEC validation in
|
||||
Unbound.
|
||||
Default is no.
|
||||
.TP
|
||||
.B serve\-expired: \fI<yes or no>
|
||||
If enabled, Unbound attempts to serve old responses from cache with a
|
||||
TTL of \fBserve\-expired\-reply\-ttl\fR in the response without waiting for the
|
||||
@@ -1825,6 +1885,9 @@ The ratelimit is in queries per second that are allowed. More queries are
|
||||
completely dropped and will not receive a reply, SERVFAIL or otherwise.
|
||||
IP ratelimiting happens before looking in the cache. This may be useful for
|
||||
mitigating amplification attacks.
|
||||
Clients with a valid DNS Cookie will bypass the ratelimit.
|
||||
If a ratelimit for such clients is still needed, \fBip\-ratelimit\-cookie\fR
|
||||
can be used instead.
|
||||
Default is 0 (disabled).
|
||||
.TP 5
|
||||
.B ip\-ratelimit\-cookie: \fI<number or 0>
|
||||
@@ -2612,11 +2675,7 @@ If Unbound cannot even find an answer in the backend, it resolves the
|
||||
query as usual, and stores the answer in the backend.
|
||||
.P
|
||||
This module interacts with the \fBserve\-expired\-*\fR options and will reply
|
||||
with expired data if Unbound is configured for that. Currently the use
|
||||
of \fBserve\-expired\-client\-timeout:\fR and
|
||||
\fBserve\-expired\-reply\-ttl:\fR is not consistent for data originating from
|
||||
the external cache as these will result in a reply with 0 TTL without trying to
|
||||
update the data first, ignoring the configured values.
|
||||
with expired data if Unbound is configured for that.
|
||||
.P
|
||||
If Unbound was built with
|
||||
\fB\-\-with\-libhiredis\fR
|
||||
@@ -2667,6 +2726,21 @@ operationally.
|
||||
If the backend database is shared by multiple Unbound instances,
|
||||
all instances must use the same secret seed.
|
||||
This option defaults to "default".
|
||||
.TP
|
||||
.B cachedb-no-store: \fI<yes or no>\fR
|
||||
If the backend should be read from, but not written to. This makes this
|
||||
instance not store dns messages in the backend. But if data is available it
|
||||
is retrieved. The default is no.
|
||||
.TP
|
||||
.B cachedb-check-when-serve-expired: \fI<yes or no>\fR
|
||||
If enabled, the cachedb is checked before an expired response is returned.
|
||||
When \fBserve\-expired\fR is enabled, without \fBserve\-expired\-client\-timeout\fR, it then
|
||||
does not immediately respond with an expired response from cache, but instead
|
||||
first checks the cachedb for valid contents, and if so returns it. If the
|
||||
cachedb also has no valid contents, the serve expired response is sent.
|
||||
If also \fBserve\-expired\-client\-timeout\fR is enabled, the expired response
|
||||
is delayed until the timeout expires. Unless the lookup succeeds within the
|
||||
timeout. The default is yes.
|
||||
.P
|
||||
The following
|
||||
.B cachedb
|
||||
@@ -2707,6 +2781,17 @@ Unbound is configured with \fBserve-expired\fR and \fBserve-expired-ttl\fR is 0,
|
||||
this option is internally reverted to "no". Redis SETEX support is required
|
||||
for this option (Redis >= 2.0.0).
|
||||
This option defaults to no.
|
||||
.TP
|
||||
.B redis-logical-db: \fI<logical database index>
|
||||
The logical database in Redis to use.
|
||||
These are databases in the same Redis instance sharing the same configuration
|
||||
and persisted in the same RDB/AOF file.
|
||||
If unsure about using this option, Redis documentation
|
||||
(https://redis.io/commands/select/) suggests not to use a single Redis instance
|
||||
for multiple unrelated applications.
|
||||
The default database in Redis is 0 while other logical databases need to be
|
||||
explicitly SELECT'ed upon connecting.
|
||||
This option defaults to 0.
|
||||
.SS DNSTAP Logging Options
|
||||
DNSTAP support, when compiled in by using \fB\-\-enable\-dnstap\fR, is enabled
|
||||
in the \fBdnstap:\fR section.
|
||||
@@ -2767,6 +2852,13 @@ Default is "".
|
||||
The version to send with messages, if "" the package version is used.
|
||||
Default is "".
|
||||
.TP
|
||||
.B dnstap-sample-rate: \fI<number>
|
||||
The sample rate for log of messages, it logs only 1/N messages. With 0 it
|
||||
is disabled. Default is 0. This is useful in a high volume environment,
|
||||
where log functionality would otherwise not be reliable. For example 10
|
||||
would spend only 1/10th time on logging, and 100 would only spend a
|
||||
hundredth of the time on logging.
|
||||
.TP
|
||||
.B dnstap-log-resolver-query-messages: \fI<yes or no>
|
||||
Enable to log resolver query messages. Default is no.
|
||||
These are messages from Unbound to upstream servers.
|
||||
|
||||
+2007
-886
File diff suppressed because it is too large
Load Diff
@@ -75,6 +75,7 @@ int dynlibmod_init(struct module_env* env, int id) {
|
||||
struct config_strlist* cfg_item = env->cfg->dynlib_file;
|
||||
struct dynlibmod_env* de = (struct dynlibmod_env*)calloc(1, sizeof(struct dynlibmod_env));
|
||||
__DYNMOD dynamic_library;
|
||||
int i;
|
||||
if (!de)
|
||||
{
|
||||
log_err("dynlibmod[%d]: malloc failure", dynlib_mod_idx);
|
||||
@@ -84,7 +85,7 @@ int dynlibmod_init(struct module_env* env, int id) {
|
||||
env->modinfo[id] = (void*) de;
|
||||
|
||||
de->fname = NULL;
|
||||
for(int i = dynlib_mod_idx;
|
||||
for(i = dynlib_mod_idx;
|
||||
i != 0 && cfg_item != NULL;
|
||||
i--, cfg_item = cfg_item->next) {}
|
||||
|
||||
@@ -296,8 +297,8 @@ inplace_cb_delete_wrapped(struct module_env* env, enum inplace_cb_list_type type
|
||||
*/
|
||||
static struct module_func_block dynlibmod_block = {
|
||||
"dynlib",
|
||||
&dynlibmod_init, &dynlibmod_deinit, &dynlibmod_operate, &dynlibmod_inform_super,
|
||||
&dynlibmod_clear, &dynlibmod_get_mem
|
||||
NULL, NULL, &dynlibmod_init, &dynlibmod_deinit, &dynlibmod_operate,
|
||||
&dynlibmod_inform_super, &dynlibmod_clear, &dynlibmod_get_mem
|
||||
};
|
||||
|
||||
struct module_func_block* dynlibmod_get_funcblock(void)
|
||||
|
||||
+66
-7
@@ -57,6 +57,9 @@
|
||||
#include "sldns/sbuffer.h"
|
||||
#include "sldns/wire2str.h"
|
||||
#include "iterator/iter_utils.h"
|
||||
#ifdef USE_CACHEDB
|
||||
#include "cachedb/cachedb.h"
|
||||
#endif
|
||||
|
||||
/** externally called */
|
||||
void
|
||||
@@ -152,10 +155,11 @@ int ecs_whitelist_check(struct query_info* qinfo,
|
||||
|
||||
/* Cache by default, might be disabled after parsing EDNS option
|
||||
* received from nameserver. */
|
||||
if(!iter_stub_fwd_no_cache(qstate, &qstate->qinfo, NULL, NULL)) {
|
||||
if(!iter_stub_fwd_no_cache(qstate, &qstate->qinfo, NULL, NULL, NULL, 0)) {
|
||||
qstate->no_cache_store = 0;
|
||||
}
|
||||
|
||||
sq->subnet_sent_no_subnet = 0;
|
||||
if(sq->ecs_server_out.subnet_validdata && ((sq->subnet_downstream &&
|
||||
qstate->env->cfg->client_subnet_always_forward) ||
|
||||
ecs_is_whitelisted(sn_env->whitelist,
|
||||
@@ -166,6 +170,14 @@ int ecs_whitelist_check(struct query_info* qinfo,
|
||||
* set. */
|
||||
if(!edns_opt_list_find(qstate->edns_opts_back_out,
|
||||
qstate->env->cfg->client_subnet_opcode)) {
|
||||
/* if the client is not wanting an EDNS subnet option,
|
||||
* omit it and store that we omitted it but actually
|
||||
* are doing EDNS subnet to the server. */
|
||||
if(sq->ecs_server_out.subnet_source_mask == 0) {
|
||||
sq->subnet_sent_no_subnet = 1;
|
||||
sq->subnet_sent = 0;
|
||||
return 1;
|
||||
}
|
||||
subnet_ecs_opt_list_append(&sq->ecs_server_out,
|
||||
&qstate->edns_opts_back_out, qstate, region);
|
||||
}
|
||||
@@ -301,9 +313,18 @@ delfunc(void *envptr, void *elemptr) {
|
||||
static size_t
|
||||
sizefunc(void *elemptr) {
|
||||
struct reply_info *elem = (struct reply_info *)elemptr;
|
||||
return sizeof (struct reply_info) - sizeof (struct rrset_ref)
|
||||
size_t s = sizeof (struct reply_info) - sizeof (struct rrset_ref)
|
||||
+ elem->rrset_count * sizeof (struct rrset_ref)
|
||||
+ elem->rrset_count * sizeof (struct ub_packed_rrset_key *);
|
||||
size_t i;
|
||||
for (i = 0; i < elem->rrset_count; i++) {
|
||||
struct ub_packed_rrset_key *key = elem->rrsets[i];
|
||||
struct packed_rrset_data *data = key->entry.data;
|
||||
s += ub_rrset_sizefunc(key, data);
|
||||
}
|
||||
if(elem->reason_bogus_str)
|
||||
s += strlen(elem->reason_bogus_str)+1;
|
||||
return s;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -343,7 +364,7 @@ update_cache(struct module_qstate *qstate, int id)
|
||||
struct slabhash *subnet_msg_cache = sne->subnet_msg_cache;
|
||||
struct ecs_data *edns = &sq->ecs_client_in;
|
||||
size_t i;
|
||||
int only_match_scope_zero;
|
||||
int only_match_scope_zero, diff_size;
|
||||
|
||||
/* We already calculated hash upon lookup (lookup_and_reply) if we were
|
||||
* allowed to look in the ECS cache */
|
||||
@@ -403,19 +424,25 @@ update_cache(struct module_qstate *qstate, int id)
|
||||
rep->ref[i].id = rep->rrsets[i]->id;
|
||||
}
|
||||
reply_info_set_ttls(rep, *qstate->env->now);
|
||||
reply_info_sortref(rep);
|
||||
rep->flags |= (BIT_RA | BIT_QR); /* fix flags to be sensible for */
|
||||
rep->flags &= ~(BIT_AA | BIT_CD);/* a reply based on the cache */
|
||||
if(edns->subnet_source_mask == 0 && edns->subnet_scope_mask == 0)
|
||||
only_match_scope_zero = 1;
|
||||
else only_match_scope_zero = 0;
|
||||
diff_size = (int)tree->size_bytes;
|
||||
addrtree_insert(tree, (addrkey_t*)edns->subnet_addr,
|
||||
edns->subnet_source_mask, sq->max_scope, rep,
|
||||
rep->ttl, *qstate->env->now, only_match_scope_zero);
|
||||
diff_size = (int)tree->size_bytes - 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);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -515,7 +542,7 @@ eval_response(struct module_qstate *qstate, int id, struct subnet_qstate *sq)
|
||||
}
|
||||
|
||||
/* We have not asked for subnet data */
|
||||
if (!sq->subnet_sent) {
|
||||
if (!sq->subnet_sent && !sq->subnet_sent_no_subnet) {
|
||||
if (s_in->subnet_validdata)
|
||||
verbose(VERB_QUERY, "subnetcache: received spurious data");
|
||||
if (sq->subnet_downstream) /* Copy back to client */
|
||||
@@ -524,7 +551,7 @@ eval_response(struct module_qstate *qstate, int id, struct subnet_qstate *sq)
|
||||
}
|
||||
|
||||
/* subnet sent but nothing came back */
|
||||
if (!s_in->subnet_validdata) {
|
||||
if (!s_in->subnet_validdata && !sq->subnet_sent_no_subnet) {
|
||||
/* The authority indicated no support for edns subnet. As a
|
||||
* consequence the answer ended up in the regular cache. It
|
||||
* is still useful to put it in the edns subnet cache for
|
||||
@@ -540,6 +567,18 @@ eval_response(struct module_qstate *qstate, int id, struct subnet_qstate *sq)
|
||||
return module_finished;
|
||||
}
|
||||
|
||||
/* Purposefully there was no sent subnet, and there is consequently
|
||||
* no subnet in the answer. If there was, use the subnet in the answer
|
||||
* anyway. But if there is not, treat it as a prefix 0 answer. */
|
||||
if(sq->subnet_sent_no_subnet && !s_in->subnet_validdata) {
|
||||
/* Fill in 0.0.0.0/0 scope 0, or ::0/0 scope 0, for caching. */
|
||||
s_in->subnet_addr_fam = s_out->subnet_addr_fam;
|
||||
s_in->subnet_source_mask = 0;
|
||||
s_in->subnet_scope_mask = 0;
|
||||
memset(s_in->subnet_addr, 0, INET6_SIZE);
|
||||
s_in->subnet_validdata = 1;
|
||||
}
|
||||
|
||||
/* Being here means we have asked for and got a subnet specific
|
||||
* answer. Also, the answer from the authority is not yet cached
|
||||
* anywhere. */
|
||||
@@ -556,6 +595,7 @@ eval_response(struct module_qstate *qstate, int id, struct subnet_qstate *sq)
|
||||
(void)edns_opt_list_remove(&qstate->edns_opts_back_out,
|
||||
qstate->env->cfg->client_subnet_opcode);
|
||||
sq->subnet_sent = 0;
|
||||
sq->subnet_sent_no_subnet = 0;
|
||||
return module_restart_next;
|
||||
}
|
||||
|
||||
@@ -565,7 +605,21 @@ eval_response(struct module_qstate *qstate, int id, struct subnet_qstate *sq)
|
||||
}
|
||||
sne->num_msg_nocache++;
|
||||
lock_rw_unlock(&sne->biglock);
|
||||
|
||||
|
||||
/* If there is an expired answer in the global cache, remove that,
|
||||
* because expired answers would otherwise resurface once the ecs data
|
||||
* expires, giving once in a while global data responses for ecs
|
||||
* domains, with serve expired enabled. */
|
||||
if(qstate->env->cfg->serve_expired) {
|
||||
msg_cache_remove(qstate->env, qstate->qinfo.qname,
|
||||
qstate->qinfo.qname_len, qstate->qinfo.qtype,
|
||||
qstate->qinfo.qclass, 0);
|
||||
#ifdef USE_CACHEDB
|
||||
if(qstate->env->cachedb_enabled)
|
||||
cachedb_msg_remove(qstate);
|
||||
#endif
|
||||
}
|
||||
|
||||
if (sq->subnet_downstream) {
|
||||
/* Client wants to see the answer, echo option back
|
||||
* and adjust the scope. */
|
||||
@@ -676,6 +730,7 @@ ecs_query_response(struct module_qstate* qstate, struct dns_msg* response,
|
||||
edns_opt_list_remove(&qstate->edns_opts_back_out,
|
||||
qstate->env->cfg->client_subnet_opcode);
|
||||
sq->subnet_sent = 0;
|
||||
sq->subnet_sent_no_subnet = 0;
|
||||
memset(&sq->ecs_server_out, 0, sizeof(sq->ecs_server_out));
|
||||
} else if (!sq->track_max_scope &&
|
||||
FLAGS_GET_RCODE(response->rep->flags) == LDNS_RCODE_NOERROR &&
|
||||
@@ -737,6 +792,9 @@ ecs_edns_back_parsed(struct module_qstate* qstate, int id,
|
||||
sq->ecs_server_in.subnet_scope_mask >
|
||||
sq->max_scope))
|
||||
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. */
|
||||
qstate->no_cache_store = 1;
|
||||
}
|
||||
|
||||
return 1;
|
||||
@@ -937,7 +995,8 @@ subnetmod_get_mem(struct module_env *env, int id)
|
||||
* The module function block
|
||||
*/
|
||||
static struct module_func_block subnetmod_block = {
|
||||
"subnetcache", &subnetmod_init, &subnetmod_deinit, &subnetmod_operate,
|
||||
"subnetcache",
|
||||
NULL, NULL, &subnetmod_init, &subnetmod_deinit, &subnetmod_operate,
|
||||
&subnetmod_inform_super, &subnetmod_clear, &subnetmod_get_mem
|
||||
};
|
||||
|
||||
|
||||
@@ -85,6 +85,13 @@ struct subnet_qstate {
|
||||
struct ecs_data ecs_server_out;
|
||||
int subnet_downstream;
|
||||
int subnet_sent;
|
||||
/**
|
||||
* If there was no subnet sent because the client used source prefix
|
||||
* length 0 for omitting the information. Then the answer is cached
|
||||
* like subnet was a /0 scope. Like the subnet_sent flag, but when
|
||||
* the EDNS subnet option is omitted because the client asked.
|
||||
*/
|
||||
int subnet_sent_no_subnet;
|
||||
/** keep track of longest received scope, set after receiving CNAME for
|
||||
* incoming QNAME. */
|
||||
int track_max_scope;
|
||||
|
||||
+1
-1
@@ -615,7 +615,7 @@ ipsecmod_get_mem(struct module_env* env, int id)
|
||||
*/
|
||||
static struct module_func_block ipsecmod_block = {
|
||||
"ipsecmod",
|
||||
&ipsecmod_init, &ipsecmod_deinit, &ipsecmod_operate,
|
||||
NULL, NULL, &ipsecmod_init, &ipsecmod_deinit, &ipsecmod_operate,
|
||||
&ipsecmod_inform_super, &ipsecmod_clear, &ipsecmod_get_mem
|
||||
};
|
||||
|
||||
|
||||
+164
-49
@@ -17,9 +17,19 @@
|
||||
#include "sldns/wire2str.h"
|
||||
#include "sldns/parseutil.h"
|
||||
|
||||
#ifdef HAVE_NET_PFVAR_H
|
||||
#include <fcntl.h>
|
||||
#include <sys/ioctl.h>
|
||||
#include <netinet/in.h>
|
||||
#include <net/if.h>
|
||||
#include <net/pfvar.h>
|
||||
typedef intptr_t filter_dev;
|
||||
#else
|
||||
#include <libmnl/libmnl.h>
|
||||
#include <linux/netfilter/nfnetlink.h>
|
||||
#include <linux/netfilter/ipset/ip_set.h>
|
||||
typedef struct mnl_socket * filter_dev;
|
||||
#endif
|
||||
|
||||
#define BUFF_LEN 256
|
||||
|
||||
@@ -41,24 +51,95 @@ static int error_response(struct module_qstate* qstate, int id, int rcode) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
static struct mnl_socket * open_mnl_socket() {
|
||||
struct mnl_socket *mnl;
|
||||
#ifdef HAVE_NET_PFVAR_H
|
||||
static void * open_filter() {
|
||||
filter_dev dev;
|
||||
|
||||
mnl = mnl_socket_open(NETLINK_NETFILTER);
|
||||
if (!mnl) {
|
||||
dev = open("/dev/pf", O_RDWR);
|
||||
if (dev == -1) {
|
||||
log_err("open(\"/dev/pf\") failed: %s", strerror(errno));
|
||||
return NULL;
|
||||
}
|
||||
else
|
||||
return (void *)dev;
|
||||
}
|
||||
#else
|
||||
static void * open_filter() {
|
||||
filter_dev dev;
|
||||
|
||||
dev = mnl_socket_open(NETLINK_NETFILTER);
|
||||
if (!dev) {
|
||||
log_err("ipset: could not open netfilter.");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (mnl_socket_bind(mnl, 0, MNL_SOCKET_AUTOPID) < 0) {
|
||||
mnl_socket_close(mnl);
|
||||
if (mnl_socket_bind(dev, 0, MNL_SOCKET_AUTOPID) < 0) {
|
||||
mnl_socket_close(dev);
|
||||
log_err("ipset: could not bind netfilter.");
|
||||
return NULL;
|
||||
}
|
||||
return mnl;
|
||||
return (void *)dev;
|
||||
}
|
||||
#endif
|
||||
|
||||
static int add_to_ipset(struct mnl_socket *mnl, const char *setname, const void *ipaddr, int af) {
|
||||
#ifdef HAVE_NET_PFVAR_H
|
||||
static int add_to_ipset(filter_dev dev, const char *setname, const void *ipaddr, int af) {
|
||||
struct pfioc_table io;
|
||||
struct pfr_addr addr;
|
||||
const char *p;
|
||||
int i;
|
||||
|
||||
bzero(&io, sizeof(io));
|
||||
bzero(&addr, sizeof(addr));
|
||||
|
||||
p = strrchr(setname, '/');
|
||||
if (p) {
|
||||
i = p - setname;
|
||||
if (i >= PATH_MAX) {
|
||||
errno = ENAMETOOLONG;
|
||||
return -1;
|
||||
}
|
||||
memcpy(io.pfrio_table.pfrt_anchor, setname, i);
|
||||
if (i < PATH_MAX)
|
||||
io.pfrio_table.pfrt_anchor[i] = '\0';
|
||||
p++;
|
||||
}
|
||||
else
|
||||
p = setname;
|
||||
|
||||
if (strlen(p) >= PF_TABLE_NAME_SIZE) {
|
||||
errno = ENAMETOOLONG;
|
||||
return -1;
|
||||
}
|
||||
strlcpy(io.pfrio_table.pfrt_name, p, PF_TABLE_NAME_SIZE);
|
||||
|
||||
io.pfrio_buffer = &addr;
|
||||
io.pfrio_size = 1;
|
||||
io.pfrio_esize = sizeof(addr);
|
||||
|
||||
switch (af) {
|
||||
case AF_INET:
|
||||
addr.pfra_ip4addr = *(struct in_addr *)ipaddr;
|
||||
addr.pfra_net = 32;
|
||||
break;
|
||||
case AF_INET6:
|
||||
addr.pfra_ip6addr = *(struct in6_addr *)ipaddr;
|
||||
addr.pfra_net = 128;
|
||||
break;
|
||||
default:
|
||||
errno = EAFNOSUPPORT;
|
||||
return -1;
|
||||
}
|
||||
addr.pfra_af = af;
|
||||
|
||||
if (ioctl(dev, DIOCRADDADDRS, &io) == -1) {
|
||||
log_err("ioctl failed: %s", strerror(errno));
|
||||
return -1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
#else
|
||||
static int add_to_ipset(filter_dev dev, const char *setname, const void *ipaddr, int af) {
|
||||
struct nlmsghdr *nlh;
|
||||
struct nfgenmsg *nfg;
|
||||
struct nlattr *nested[2];
|
||||
@@ -91,14 +172,15 @@ static int add_to_ipset(struct mnl_socket *mnl, const char *setname, const void
|
||||
mnl_attr_nest_end(nlh, nested[1]);
|
||||
mnl_attr_nest_end(nlh, nested[0]);
|
||||
|
||||
if (mnl_socket_sendto(mnl, nlh, nlh->nlmsg_len) < 0) {
|
||||
if (mnl_socket_sendto(dev, nlh, nlh->nlmsg_len) < 0) {
|
||||
return -1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
#endif
|
||||
|
||||
static void
|
||||
ipset_add_rrset_data(struct ipset_env *ie, struct mnl_socket *mnl,
|
||||
ipset_add_rrset_data(struct ipset_env *ie,
|
||||
struct packed_rrset_data *d, const char* setname, int af,
|
||||
const char* dname)
|
||||
{
|
||||
@@ -123,12 +205,16 @@ ipset_add_rrset_data(struct ipset_env *ie, struct mnl_socket *mnl,
|
||||
snprintf(ip, sizeof(ip), "(inet_ntop_error)");
|
||||
verbose(VERB_QUERY, "ipset: add %s to %s for %s", ip, setname, dname);
|
||||
}
|
||||
ret = add_to_ipset(mnl, setname, rr_data + 2, af);
|
||||
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);
|
||||
|
||||
mnl_socket_close(mnl);
|
||||
ie->mnl = NULL;
|
||||
#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;
|
||||
}
|
||||
}
|
||||
@@ -137,8 +223,8 @@ ipset_add_rrset_data(struct ipset_env *ie, struct mnl_socket *mnl,
|
||||
|
||||
static int
|
||||
ipset_check_zones_for_rrset(struct module_env *env, struct ipset_env *ie,
|
||||
struct mnl_socket *mnl, struct ub_packed_rrset_key *rrset,
|
||||
const char *qname, const int qlen, const char *setname, int af)
|
||||
struct ub_packed_rrset_key *rrset, const char *qname, int qlen,
|
||||
const char *setname, int af)
|
||||
{
|
||||
static char dname[BUFF_LEN];
|
||||
const char *ds, *qs;
|
||||
@@ -152,23 +238,31 @@ ipset_check_zones_for_rrset(struct module_env *env, struct ipset_env *ie,
|
||||
log_err("bad domain name");
|
||||
return -1;
|
||||
}
|
||||
if (dname[dlen - 1] == '.') {
|
||||
dlen--;
|
||||
}
|
||||
if (qname[qlen - 1] == '.') {
|
||||
qlen--;
|
||||
}
|
||||
|
||||
for (p = env->cfg->local_zones_ipset; p; p = p->next) {
|
||||
ds = NULL;
|
||||
qs = NULL;
|
||||
plen = strlen(p->str);
|
||||
if (p->str[plen - 1] == '.') {
|
||||
plen--;
|
||||
}
|
||||
|
||||
if (dlen >= plen) {
|
||||
if (dlen == plen || (dlen > plen && dname[dlen - plen - 1] == '.' )) {
|
||||
ds = dname + (dlen - plen);
|
||||
}
|
||||
if (qlen >= plen) {
|
||||
if (qlen == plen || (qlen > plen && qname[qlen - plen - 1] == '.' )) {
|
||||
qs = qname + (qlen - plen);
|
||||
}
|
||||
if ((ds && strncasecmp(p->str, ds, plen) == 0)
|
||||
|| (qs && strncasecmp(p->str, qs, plen) == 0)) {
|
||||
d = (struct packed_rrset_data*)rrset->entry.data;
|
||||
ipset_add_rrset_data(ie, mnl, d, setname,
|
||||
af, dname);
|
||||
ipset_add_rrset_data(ie, d, setname, af, dname);
|
||||
break;
|
||||
}
|
||||
}
|
||||
@@ -178,7 +272,6 @@ ipset_check_zones_for_rrset(struct module_env *env, struct ipset_env *ie,
|
||||
static int ipset_update(struct module_env *env, struct dns_msg *return_msg,
|
||||
struct query_info qinfo, struct ipset_env *ie)
|
||||
{
|
||||
struct mnl_socket *mnl;
|
||||
size_t i;
|
||||
const char *setname;
|
||||
struct ub_packed_rrset_key *rrset;
|
||||
@@ -186,15 +279,17 @@ static int ipset_update(struct module_env *env, struct dns_msg *return_msg,
|
||||
static char qname[BUFF_LEN];
|
||||
int qlen;
|
||||
|
||||
mnl = (struct mnl_socket *)ie->mnl;
|
||||
if (!mnl) {
|
||||
#ifdef HAVE_NET_PFVAR_H
|
||||
#else
|
||||
if (!ie->dev) {
|
||||
/* retry to create mnl socket */
|
||||
mnl = open_mnl_socket();
|
||||
if (!mnl) {
|
||||
ie->dev = open_filter();
|
||||
if (!ie->dev) {
|
||||
log_warn("ipset open_filter failed");
|
||||
return -1;
|
||||
}
|
||||
ie->mnl = mnl;
|
||||
}
|
||||
#endif
|
||||
|
||||
qlen = sldns_wire2str_dname_buf(qinfo.qname, qinfo.qname_len,
|
||||
qname, BUFF_LEN);
|
||||
@@ -217,8 +312,8 @@ static int ipset_update(struct module_env *env, struct dns_msg *return_msg,
|
||||
}
|
||||
|
||||
if (setname) {
|
||||
if(ipset_check_zones_for_rrset(env, ie, mnl, rrset,
|
||||
qname, qlen, setname, af) == -1)
|
||||
if(ipset_check_zones_for_rrset(env, ie, rrset, qname,
|
||||
qlen, setname, af) == -1)
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
@@ -226,7 +321,7 @@ static int ipset_update(struct module_env *env, struct dns_msg *return_msg,
|
||||
return 0;
|
||||
}
|
||||
|
||||
int ipset_init(struct module_env* env, int id) {
|
||||
int ipset_startup(struct module_env* env, int id) {
|
||||
struct ipset_env *ipset_env;
|
||||
|
||||
ipset_env = (struct ipset_env *)calloc(1, sizeof(struct ipset_env));
|
||||
@@ -237,7 +332,43 @@ int ipset_init(struct module_env* env, int id) {
|
||||
|
||||
env->modinfo[id] = (void *)ipset_env;
|
||||
|
||||
ipset_env->mnl = NULL;
|
||||
#ifdef HAVE_NET_PFVAR_H
|
||||
ipset_env->dev = open_filter();
|
||||
if (!ipset_env->dev) {
|
||||
log_err("ipset open_filter failed");
|
||||
return 0;
|
||||
}
|
||||
#else
|
||||
ipset_env->dev = NULL;
|
||||
#endif
|
||||
return 1;
|
||||
}
|
||||
|
||||
void ipset_destartup(struct module_env* env, int id) {
|
||||
filter_dev dev;
|
||||
struct ipset_env *ipset_env;
|
||||
|
||||
if (!env || !env->modinfo[id]) {
|
||||
return;
|
||||
}
|
||||
ipset_env = (struct ipset_env*)env->modinfo[id];
|
||||
|
||||
dev = (filter_dev)ipset_env->dev;
|
||||
if (dev) {
|
||||
#if HAVE_NET_PFVAR_H
|
||||
close(dev);
|
||||
#else
|
||||
mnl_socket_close(dev);
|
||||
#endif
|
||||
ipset_env->dev = NULL;
|
||||
}
|
||||
|
||||
free(ipset_env);
|
||||
env->modinfo[id] = NULL;
|
||||
}
|
||||
|
||||
int ipset_init(struct module_env* env, int id) {
|
||||
struct ipset_env *ipset_env = env->modinfo[id];
|
||||
|
||||
ipset_env->name_v4 = env->cfg->ipset_name_v4;
|
||||
ipset_env->name_v6 = env->cfg->ipset_name_v6;
|
||||
@@ -253,24 +384,8 @@ int ipset_init(struct module_env* env, int id) {
|
||||
return 1;
|
||||
}
|
||||
|
||||
void ipset_deinit(struct module_env *env, int id) {
|
||||
struct mnl_socket *mnl;
|
||||
struct ipset_env *ipset_env;
|
||||
|
||||
if (!env || !env->modinfo[id]) {
|
||||
return;
|
||||
}
|
||||
|
||||
ipset_env = (struct ipset_env *)env->modinfo[id];
|
||||
|
||||
mnl = (struct mnl_socket *)ipset_env->mnl;
|
||||
if (mnl) {
|
||||
mnl_socket_close(mnl);
|
||||
ipset_env->mnl = NULL;
|
||||
}
|
||||
|
||||
free(ipset_env);
|
||||
env->modinfo[id] = NULL;
|
||||
void ipset_deinit(struct module_env *ATTR_UNUSED(env), int ATTR_UNUSED(id)) {
|
||||
/* nothing */
|
||||
}
|
||||
|
||||
static int ipset_new(struct module_qstate* qstate, int id) {
|
||||
@@ -376,8 +491,8 @@ size_t ipset_get_mem(struct module_env *env, int id) {
|
||||
*/
|
||||
static struct module_func_block ipset_block = {
|
||||
"ipset",
|
||||
&ipset_init, &ipset_deinit, &ipset_operate,
|
||||
&ipset_inform_super, &ipset_clear, &ipset_get_mem
|
||||
&ipset_startup, &ipset_destartup, &ipset_init, &ipset_deinit,
|
||||
&ipset_operate, &ipset_inform_super, &ipset_clear, &ipset_get_mem
|
||||
};
|
||||
|
||||
struct module_func_block * ipset_get_funcblock(void) {
|
||||
|
||||
+5
-1
@@ -37,7 +37,7 @@ extern "C" {
|
||||
#endif
|
||||
|
||||
struct ipset_env {
|
||||
void* mnl;
|
||||
void* dev;
|
||||
|
||||
int v4_enabled;
|
||||
int v6_enabled;
|
||||
@@ -50,6 +50,10 @@ struct ipset_qstate {
|
||||
int dummy;
|
||||
};
|
||||
|
||||
/** Startup the ipset module */
|
||||
int ipset_startup(struct module_env* env, int id);
|
||||
/** Destartup the ipset module */
|
||||
void ipset_destartup(struct module_env* env, int id);
|
||||
/** Init the ipset module */
|
||||
int ipset_init(struct module_env* env, int id);
|
||||
/** Deinit the ipset module */
|
||||
|
||||
+93
-27
@@ -71,6 +71,7 @@ forwards_create(void)
|
||||
sizeof(struct iter_forwards));
|
||||
if(!fwd)
|
||||
return NULL;
|
||||
lock_rw_init(&fwd->lock);
|
||||
return fwd;
|
||||
}
|
||||
|
||||
@@ -100,6 +101,7 @@ forwards_delete(struct iter_forwards* fwd)
|
||||
{
|
||||
if(!fwd)
|
||||
return;
|
||||
lock_rw_destroy(&fwd->lock);
|
||||
fwd_del_tree(fwd);
|
||||
free(fwd);
|
||||
}
|
||||
@@ -332,45 +334,64 @@ make_stub_holes(struct iter_forwards* fwd, struct config_file* cfg)
|
||||
int
|
||||
forwards_apply_cfg(struct iter_forwards* fwd, struct config_file* cfg)
|
||||
{
|
||||
if(fwd->tree) {
|
||||
lock_unprotect(&fwd->lock, fwd->tree);
|
||||
}
|
||||
fwd_del_tree(fwd);
|
||||
fwd->tree = rbtree_create(fwd_cmp);
|
||||
if(!fwd->tree)
|
||||
return 0;
|
||||
lock_protect(&fwd->lock, fwd->tree, sizeof(*fwd->tree));
|
||||
|
||||
lock_rw_wrlock(&fwd->lock);
|
||||
/* read forward zones */
|
||||
if(!read_forwards(fwd, cfg))
|
||||
if(!read_forwards(fwd, cfg)) {
|
||||
lock_rw_unlock(&fwd->lock);
|
||||
return 0;
|
||||
if(!make_stub_holes(fwd, cfg))
|
||||
}
|
||||
if(!make_stub_holes(fwd, cfg)) {
|
||||
lock_rw_unlock(&fwd->lock);
|
||||
return 0;
|
||||
}
|
||||
fwd_init_parents(fwd);
|
||||
lock_rw_unlock(&fwd->lock);
|
||||
return 1;
|
||||
}
|
||||
|
||||
struct delegpt*
|
||||
forwards_find(struct iter_forwards* fwd, uint8_t* qname, uint16_t qclass)
|
||||
forwards_find(struct iter_forwards* fwd, uint8_t* qname, uint16_t qclass,
|
||||
int nolock)
|
||||
{
|
||||
rbnode_type* res = NULL;
|
||||
struct iter_forward_zone* res;
|
||||
struct iter_forward_zone key;
|
||||
int has_dp;
|
||||
key.node.key = &key;
|
||||
key.dclass = qclass;
|
||||
key.name = qname;
|
||||
key.namelabs = dname_count_size_labels(qname, &key.namelen);
|
||||
res = rbtree_search(fwd->tree, &key);
|
||||
if(res) return ((struct iter_forward_zone*)res)->dp;
|
||||
return NULL;
|
||||
/* lock_() calls are macros that could be nothing, surround in {} */
|
||||
if(!nolock) { lock_rw_rdlock(&fwd->lock); }
|
||||
res = (struct iter_forward_zone*)rbtree_search(fwd->tree, &key);
|
||||
has_dp = res && res->dp;
|
||||
if(!has_dp && !nolock) { lock_rw_unlock(&fwd->lock); }
|
||||
return has_dp?res->dp:NULL;
|
||||
}
|
||||
|
||||
struct delegpt*
|
||||
forwards_lookup(struct iter_forwards* fwd, uint8_t* qname, uint16_t qclass)
|
||||
forwards_lookup(struct iter_forwards* fwd, uint8_t* qname, uint16_t qclass,
|
||||
int nolock)
|
||||
{
|
||||
/* lookup the forward zone in the tree */
|
||||
rbnode_type* res = NULL;
|
||||
struct iter_forward_zone *result;
|
||||
struct iter_forward_zone key;
|
||||
int has_dp;
|
||||
key.node.key = &key;
|
||||
key.dclass = qclass;
|
||||
key.name = qname;
|
||||
key.namelabs = dname_count_size_labels(qname, &key.namelen);
|
||||
/* lock_() calls are macros that could be nothing, surround in {} */
|
||||
if(!nolock) { lock_rw_rdlock(&fwd->lock); }
|
||||
if(rbtree_find_less_equal(fwd->tree, &key, &res)) {
|
||||
/* exact */
|
||||
result = (struct iter_forward_zone*)res;
|
||||
@@ -378,8 +399,10 @@ forwards_lookup(struct iter_forwards* fwd, uint8_t* qname, uint16_t qclass)
|
||||
/* smaller element (or no element) */
|
||||
int m;
|
||||
result = (struct iter_forward_zone*)res;
|
||||
if(!result || result->dclass != qclass)
|
||||
if(!result || result->dclass != qclass) {
|
||||
if(!nolock) { lock_rw_unlock(&fwd->lock); }
|
||||
return NULL;
|
||||
}
|
||||
/* count number of labels matched */
|
||||
(void)dname_lab_cmp(result->name, result->namelabs, key.name,
|
||||
key.namelabs, &m);
|
||||
@@ -389,20 +412,22 @@ forwards_lookup(struct iter_forwards* fwd, uint8_t* qname, uint16_t qclass)
|
||||
result = result->parent;
|
||||
}
|
||||
}
|
||||
if(result)
|
||||
return result->dp;
|
||||
return NULL;
|
||||
has_dp = result && result->dp;
|
||||
if(!has_dp && !nolock) { lock_rw_unlock(&fwd->lock); }
|
||||
return has_dp?result->dp:NULL;
|
||||
}
|
||||
|
||||
struct delegpt*
|
||||
forwards_lookup_root(struct iter_forwards* fwd, uint16_t qclass)
|
||||
forwards_lookup_root(struct iter_forwards* fwd, uint16_t qclass, int nolock)
|
||||
{
|
||||
uint8_t root = 0;
|
||||
return forwards_lookup(fwd, &root, qclass);
|
||||
return forwards_lookup(fwd, &root, qclass, nolock);
|
||||
}
|
||||
|
||||
int
|
||||
forwards_next_root(struct iter_forwards* fwd, uint16_t* dclass)
|
||||
/* Finds next root item in forwards lookup tree.
|
||||
* Caller needs to handle locking of the forwards structure. */
|
||||
static int
|
||||
next_root_locked(struct iter_forwards* fwd, uint16_t* dclass)
|
||||
{
|
||||
struct iter_forward_zone key;
|
||||
rbnode_type* n;
|
||||
@@ -419,7 +444,7 @@ forwards_next_root(struct iter_forwards* fwd, uint16_t* dclass)
|
||||
}
|
||||
/* root not first item? search for higher items */
|
||||
*dclass = p->dclass + 1;
|
||||
return forwards_next_root(fwd, dclass);
|
||||
return next_root_locked(fwd, dclass);
|
||||
}
|
||||
/* find class n in tree, we may get a direct hit, or if we don't
|
||||
* this is the last item of the previous class so rbtree_next() takes
|
||||
@@ -447,10 +472,21 @@ forwards_next_root(struct iter_forwards* fwd, uint16_t* dclass)
|
||||
}
|
||||
/* not a root node, return next higher item */
|
||||
*dclass = p->dclass+1;
|
||||
return forwards_next_root(fwd, dclass);
|
||||
return next_root_locked(fwd, dclass);
|
||||
}
|
||||
}
|
||||
|
||||
int
|
||||
forwards_next_root(struct iter_forwards* fwd, uint16_t* dclass, int nolock)
|
||||
{
|
||||
int ret;
|
||||
/* lock_() calls are macros that could be nothing, surround in {} */
|
||||
if(!nolock) { lock_rw_rdlock(&fwd->lock); }
|
||||
ret = next_root_locked(fwd, dclass);
|
||||
if(!nolock) { lock_rw_unlock(&fwd->lock); }
|
||||
return ret;
|
||||
}
|
||||
|
||||
size_t
|
||||
forwards_get_mem(struct iter_forwards* fwd)
|
||||
{
|
||||
@@ -458,10 +494,12 @@ forwards_get_mem(struct iter_forwards* fwd)
|
||||
size_t s;
|
||||
if(!fwd)
|
||||
return 0;
|
||||
lock_rw_rdlock(&fwd->lock);
|
||||
s = sizeof(*fwd) + sizeof(*fwd->tree);
|
||||
RBTREE_FOR(p, struct iter_forward_zone*, fwd->tree) {
|
||||
s += sizeof(*p) + p->namelen + delegpt_get_mem(p->dp);
|
||||
}
|
||||
lock_rw_unlock(&fwd->lock);
|
||||
return s;
|
||||
}
|
||||
|
||||
@@ -477,50 +515,78 @@ fwd_zone_find(struct iter_forwards* fwd, uint16_t c, uint8_t* nm)
|
||||
}
|
||||
|
||||
int
|
||||
forwards_add_zone(struct iter_forwards* fwd, uint16_t c, struct delegpt* dp)
|
||||
forwards_add_zone(struct iter_forwards* fwd, uint16_t c, struct delegpt* dp,
|
||||
int nolock)
|
||||
{
|
||||
struct iter_forward_zone *z;
|
||||
/* lock_() calls are macros that could be nothing, surround in {} */
|
||||
if(!nolock) { lock_rw_wrlock(&fwd->lock); }
|
||||
if((z=fwd_zone_find(fwd, c, dp->name)) != NULL) {
|
||||
(void)rbtree_delete(fwd->tree, &z->node);
|
||||
fwd_zone_free(z);
|
||||
}
|
||||
if(!forwards_insert(fwd, c, dp))
|
||||
if(!forwards_insert(fwd, c, dp)) {
|
||||
if(!nolock) { lock_rw_unlock(&fwd->lock); }
|
||||
return 0;
|
||||
}
|
||||
fwd_init_parents(fwd);
|
||||
if(!nolock) { lock_rw_unlock(&fwd->lock); }
|
||||
return 1;
|
||||
}
|
||||
|
||||
void
|
||||
forwards_delete_zone(struct iter_forwards* fwd, uint16_t c, uint8_t* nm)
|
||||
forwards_delete_zone(struct iter_forwards* fwd, uint16_t c, uint8_t* nm,
|
||||
int nolock)
|
||||
{
|
||||
struct iter_forward_zone *z;
|
||||
if(!(z=fwd_zone_find(fwd, c, nm)))
|
||||
/* lock_() calls are macros that could be nothing, surround in {} */
|
||||
if(!nolock) { lock_rw_wrlock(&fwd->lock); }
|
||||
if(!(z=fwd_zone_find(fwd, c, nm))) {
|
||||
if(!nolock) { lock_rw_unlock(&fwd->lock); }
|
||||
return; /* nothing to do */
|
||||
}
|
||||
(void)rbtree_delete(fwd->tree, &z->node);
|
||||
fwd_zone_free(z);
|
||||
fwd_init_parents(fwd);
|
||||
if(!nolock) { lock_rw_unlock(&fwd->lock); }
|
||||
}
|
||||
|
||||
int
|
||||
forwards_add_stub_hole(struct iter_forwards* fwd, uint16_t c, uint8_t* nm)
|
||||
forwards_add_stub_hole(struct iter_forwards* fwd, uint16_t c, uint8_t* nm,
|
||||
int nolock)
|
||||
{
|
||||
/* lock_() calls are macros that could be nothing, surround in {} */
|
||||
if(!nolock) { lock_rw_wrlock(&fwd->lock); }
|
||||
if(fwd_zone_find(fwd, c, nm) != NULL) {
|
||||
if(!nolock) { lock_rw_unlock(&fwd->lock); }
|
||||
return 1; /* already a stub zone there */
|
||||
}
|
||||
if(!fwd_add_stub_hole(fwd, c, nm)) {
|
||||
if(!nolock) { lock_rw_unlock(&fwd->lock); }
|
||||
return 0;
|
||||
}
|
||||
fwd_init_parents(fwd);
|
||||
if(!nolock) { lock_rw_unlock(&fwd->lock); }
|
||||
return 1;
|
||||
}
|
||||
|
||||
void
|
||||
forwards_delete_stub_hole(struct iter_forwards* fwd, uint16_t c, uint8_t* nm)
|
||||
forwards_delete_stub_hole(struct iter_forwards* fwd, uint16_t c,
|
||||
uint8_t* nm, int nolock)
|
||||
{
|
||||
struct iter_forward_zone *z;
|
||||
if(!(z=fwd_zone_find(fwd, c, nm)))
|
||||
/* lock_() calls are macros that could be nothing, surround in {} */
|
||||
if(!nolock) { lock_rw_wrlock(&fwd->lock); }
|
||||
if(!(z=fwd_zone_find(fwd, c, nm))) {
|
||||
if(!nolock) { lock_rw_unlock(&fwd->lock); }
|
||||
return; /* nothing to do */
|
||||
if(z->dp != NULL)
|
||||
}
|
||||
if(z->dp != NULL) {
|
||||
if(!nolock) { lock_rw_unlock(&fwd->lock); }
|
||||
return; /* not a stub hole */
|
||||
}
|
||||
(void)rbtree_delete(fwd->tree, &z->node);
|
||||
fwd_zone_free(z);
|
||||
fwd_init_parents(fwd);
|
||||
if(!nolock) { lock_rw_unlock(&fwd->lock); }
|
||||
}
|
||||
|
||||
|
||||
+49
-11
@@ -43,6 +43,7 @@
|
||||
#ifndef ITERATOR_ITER_FWD_H
|
||||
#define ITERATOR_ITER_FWD_H
|
||||
#include "util/rbtree.h"
|
||||
#include "util/locks.h"
|
||||
struct config_file;
|
||||
struct delegpt;
|
||||
|
||||
@@ -50,6 +51,11 @@ struct delegpt;
|
||||
* Iterator forward zones structure
|
||||
*/
|
||||
struct iter_forwards {
|
||||
/** lock on the forwards tree.
|
||||
* When grabbing both this lock and the anchors.lock, this lock
|
||||
* is grabbed first. When grabbing both this lock and the hints.lock
|
||||
* this lock is grabbed first. */
|
||||
lock_rw_type lock;
|
||||
/**
|
||||
* Zones are stored in this tree. Sort order is specially chosen.
|
||||
* first sorted on qclass. Then on dname in nsec-like order, so that
|
||||
@@ -106,47 +112,65 @@ int forwards_apply_cfg(struct iter_forwards* fwd, struct config_file* cfg);
|
||||
|
||||
/**
|
||||
* Find forward zone exactly by name
|
||||
* The return value is contents of the forwards structure.
|
||||
* Caller should lock and unlock a readlock on the forwards structure if nolock
|
||||
* is set.
|
||||
* Otherwise caller should unlock the readlock on the forwards structure if a
|
||||
* value was returned.
|
||||
* @param fwd: forward storage.
|
||||
* @param qname: The qname of the query.
|
||||
* @param qclass: The qclass of the query.
|
||||
* @param nolock: Skip locking, locking is handled by the caller.
|
||||
* @return: A delegation point or null.
|
||||
*/
|
||||
struct delegpt* forwards_find(struct iter_forwards* fwd, uint8_t* qname,
|
||||
uint16_t qclass);
|
||||
uint16_t qclass, int nolock);
|
||||
|
||||
/**
|
||||
* Find forward zone information
|
||||
* For this qname/qclass find forward zone information, returns delegation
|
||||
* point with server names and addresses, or NULL if no forwarding is needed.
|
||||
* The return value is contents of the forwards structure.
|
||||
* Caller should lock and unlock a readlock on the forwards structure if nolock
|
||||
* is set.
|
||||
* Otherwise caller should unlock the readlock on the forwards structure if a
|
||||
* value was returned.
|
||||
*
|
||||
* @param fwd: forward storage.
|
||||
* @param qname: The qname of the query.
|
||||
* @param qclass: The qclass of the query.
|
||||
* @param nolock: Skip locking, locking is handled by the caller.
|
||||
* @return: A delegation point if the query has to be forwarded to that list,
|
||||
* otherwise null.
|
||||
*/
|
||||
struct delegpt* forwards_lookup(struct iter_forwards* fwd,
|
||||
uint8_t* qname, uint16_t qclass);
|
||||
struct delegpt* forwards_lookup(struct iter_forwards* fwd,
|
||||
uint8_t* qname, uint16_t qclass, int nolock);
|
||||
|
||||
/**
|
||||
* Same as forwards_lookup, but for the root only
|
||||
* @param fwd: forward storage.
|
||||
* @param qclass: The qclass of the query.
|
||||
* @param nolock: Skip locking, locking is handled by the caller.
|
||||
* @return: A delegation point if root forward exists, otherwise null.
|
||||
*/
|
||||
struct delegpt* forwards_lookup_root(struct iter_forwards* fwd,
|
||||
uint16_t qclass);
|
||||
struct delegpt* forwards_lookup_root(struct iter_forwards* fwd,
|
||||
uint16_t qclass, int nolock);
|
||||
|
||||
/**
|
||||
* Find next root item in forwards lookup tree.
|
||||
* Handles its own locking unless nolock is set. In that case the caller
|
||||
* should lock and unlock a readlock on the forwards structure.
|
||||
* @param fwd: the forward storage
|
||||
* @param qclass: class to look at next, or higher.
|
||||
* @param nolock: Skip locking, locking is handled by the caller.
|
||||
* @return false if none found, or if true stored in qclass.
|
||||
*/
|
||||
int forwards_next_root(struct iter_forwards* fwd, uint16_t* qclass);
|
||||
int forwards_next_root(struct iter_forwards* fwd, uint16_t* qclass,
|
||||
int nolock);
|
||||
|
||||
/**
|
||||
* Get memory in use by forward storage
|
||||
* Locks and unlocks the structure.
|
||||
* @param fwd: forward storage.
|
||||
* @return bytes in use
|
||||
*/
|
||||
@@ -158,42 +182,56 @@ int fwd_cmp(const void* k1, const void* k2);
|
||||
/**
|
||||
* Add zone to forward structure. For external use since it recalcs
|
||||
* the tree parents.
|
||||
* Handles its own locking unless nolock is set. In that case the caller
|
||||
* should lock and unlock a writelock on the forwards structure.
|
||||
* @param fwd: the forward data structure
|
||||
* @param c: class of zone
|
||||
* @param dp: delegation point with name and target nameservers for new
|
||||
* forward zone. malloced.
|
||||
* @param nolock: Skip locking, locking is handled by the caller.
|
||||
* @return false on failure (out of memory);
|
||||
*/
|
||||
int forwards_add_zone(struct iter_forwards* fwd, uint16_t c,
|
||||
struct delegpt* dp);
|
||||
int forwards_add_zone(struct iter_forwards* fwd, uint16_t c,
|
||||
struct delegpt* dp, int nolock);
|
||||
|
||||
/**
|
||||
* Remove zone from forward structure. For external use since it
|
||||
* recalcs the tree parents.
|
||||
* Handles its own locking unless nolock is set. In that case the caller
|
||||
* should lock and unlock a writelock on the forwards structure.
|
||||
* @param fwd: the forward data structure
|
||||
* @param c: class of zone
|
||||
* @param nm: name of zone (in uncompressed wireformat).
|
||||
* @param nolock: Skip locking, locking is handled by the caller.
|
||||
*/
|
||||
void forwards_delete_zone(struct iter_forwards* fwd, uint16_t c, uint8_t* nm);
|
||||
void forwards_delete_zone(struct iter_forwards* fwd, uint16_t c,
|
||||
uint8_t* nm, int nolock);
|
||||
|
||||
/**
|
||||
* Add stub hole (empty entry in forward table, that makes resolution skip
|
||||
* a forward-zone because the stub zone should override the forward zone).
|
||||
* Does not add one if not necessary.
|
||||
* Handles its own locking unless nolock is set. In that case the caller
|
||||
* should lock and unlock a writelock on the forwards structure.
|
||||
* @param fwd: the forward data structure
|
||||
* @param c: class of zone
|
||||
* @param nm: name of zone (in uncompressed wireformat).
|
||||
* @param nolock: Skip locking, locking is handled by the caller.
|
||||
* @return false on failure (out of memory);
|
||||
*/
|
||||
int forwards_add_stub_hole(struct iter_forwards* fwd, uint16_t c, uint8_t* nm);
|
||||
int forwards_add_stub_hole(struct iter_forwards* fwd, uint16_t c,
|
||||
uint8_t* nm, int nolock);
|
||||
|
||||
/**
|
||||
* Remove stub hole, if one exists.
|
||||
* Handles its own locking unless nolock is set. In that case the caller
|
||||
* should lock and unlock a writelock on the forwards structure.
|
||||
* @param fwd: the forward data structure
|
||||
* @param c: class of zone
|
||||
* @param nm: name of zone (in uncompressed wireformat).
|
||||
* @param nolock: Skip locking, locking is handled by the caller.
|
||||
*/
|
||||
void forwards_delete_stub_hole(struct iter_forwards* fwd, uint16_t c,
|
||||
uint8_t* nm);
|
||||
uint8_t* nm, int nolock);
|
||||
|
||||
#endif /* ITERATOR_ITER_FWD_H */
|
||||
|
||||
+76
-26
@@ -57,6 +57,8 @@ hints_create(void)
|
||||
sizeof(struct iter_hints));
|
||||
if(!hints)
|
||||
return NULL;
|
||||
lock_rw_init(&hints->lock);
|
||||
lock_protect(&hints->lock, &hints->tree, sizeof(hints->tree));
|
||||
return hints;
|
||||
}
|
||||
|
||||
@@ -83,6 +85,7 @@ hints_delete(struct iter_hints* hints)
|
||||
{
|
||||
if(!hints)
|
||||
return;
|
||||
lock_rw_destroy(&hints->lock);
|
||||
hints_del_tree(hints);
|
||||
free(hints);
|
||||
}
|
||||
@@ -129,7 +132,7 @@ compile_time_root_prime(int do_ip4, int do_ip6)
|
||||
dp->has_parent_side_NS = 1;
|
||||
if(do_ip4) {
|
||||
if(!ah(dp, "A.ROOT-SERVERS.NET.", "198.41.0.4")) goto failed;
|
||||
if(!ah(dp, "B.ROOT-SERVERS.NET.", "199.9.14.201")) goto failed;
|
||||
if(!ah(dp, "B.ROOT-SERVERS.NET.", "170.247.170.2")) goto failed;
|
||||
if(!ah(dp, "C.ROOT-SERVERS.NET.", "192.33.4.12")) goto failed;
|
||||
if(!ah(dp, "D.ROOT-SERVERS.NET.", "199.7.91.13")) goto failed;
|
||||
if(!ah(dp, "E.ROOT-SERVERS.NET.", "192.203.230.10")) goto failed;
|
||||
@@ -144,7 +147,7 @@ compile_time_root_prime(int do_ip4, int do_ip6)
|
||||
}
|
||||
if(do_ip6) {
|
||||
if(!ah(dp, "A.ROOT-SERVERS.NET.", "2001:503:ba3e::2:30")) goto failed;
|
||||
if(!ah(dp, "B.ROOT-SERVERS.NET.", "2001:500:200::b")) goto failed;
|
||||
if(!ah(dp, "B.ROOT-SERVERS.NET.", "2801:1b8:10::b")) goto failed;
|
||||
if(!ah(dp, "C.ROOT-SERVERS.NET.", "2001:500:2::c")) goto failed;
|
||||
if(!ah(dp, "D.ROOT-SERVERS.NET.", "2001:500:2d::d")) goto failed;
|
||||
if(!ah(dp, "E.ROOT-SERVERS.NET.", "2001:500:a8::e")) goto failed;
|
||||
@@ -438,47 +441,70 @@ read_root_hints_list(struct iter_hints* hints, struct config_file* cfg)
|
||||
int
|
||||
hints_apply_cfg(struct iter_hints* hints, struct config_file* cfg)
|
||||
{
|
||||
int nolock = 1;
|
||||
lock_rw_wrlock(&hints->lock);
|
||||
hints_del_tree(hints);
|
||||
name_tree_init(&hints->tree);
|
||||
|
||||
|
||||
/* read root hints */
|
||||
if(!read_root_hints_list(hints, cfg))
|
||||
if(!read_root_hints_list(hints, cfg)) {
|
||||
lock_rw_unlock(&hints->lock);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* read stub hints */
|
||||
if(!read_stubs(hints, cfg))
|
||||
if(!read_stubs(hints, cfg)) {
|
||||
lock_rw_unlock(&hints->lock);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* use fallback compiletime root hints */
|
||||
if(!hints_lookup_root(hints, LDNS_RR_CLASS_IN)) {
|
||||
if(!hints_find_root(hints, LDNS_RR_CLASS_IN, nolock)) {
|
||||
struct delegpt* dp = compile_time_root_prime(cfg->do_ip4,
|
||||
cfg->do_ip6);
|
||||
verbose(VERB_ALGO, "no config, using builtin root hints.");
|
||||
if(!dp)
|
||||
if(!dp) {
|
||||
lock_rw_unlock(&hints->lock);
|
||||
return 0;
|
||||
if(!hints_insert(hints, LDNS_RR_CLASS_IN, dp, 0))
|
||||
}
|
||||
if(!hints_insert(hints, LDNS_RR_CLASS_IN, dp, 0)) {
|
||||
lock_rw_unlock(&hints->lock);
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
name_tree_init_parents(&hints->tree);
|
||||
lock_rw_unlock(&hints->lock);
|
||||
return 1;
|
||||
}
|
||||
|
||||
struct delegpt*
|
||||
hints_lookup_root(struct iter_hints* hints, uint16_t qclass)
|
||||
struct delegpt*
|
||||
hints_find(struct iter_hints* hints, uint8_t* qname, uint16_t qclass,
|
||||
int nolock)
|
||||
{
|
||||
struct iter_hints_stub *stub;
|
||||
size_t len;
|
||||
int has_dp;
|
||||
int labs = dname_count_size_labels(qname, &len);
|
||||
/* lock_() calls are macros that could be nothing, surround in {} */
|
||||
if(!nolock) { lock_rw_rdlock(&hints->lock); }
|
||||
stub = (struct iter_hints_stub*)name_tree_find(&hints->tree,
|
||||
qname, len, labs, qclass);
|
||||
has_dp = stub && stub->dp;
|
||||
if(!has_dp && !nolock) { lock_rw_unlock(&hints->lock); }
|
||||
return has_dp?stub->dp:NULL;
|
||||
}
|
||||
|
||||
struct delegpt*
|
||||
hints_find_root(struct iter_hints* hints, uint16_t qclass, int nolock)
|
||||
{
|
||||
uint8_t rootlab = 0;
|
||||
struct iter_hints_stub *stub;
|
||||
stub = (struct iter_hints_stub*)name_tree_find(&hints->tree,
|
||||
&rootlab, 1, 1, qclass);
|
||||
if(!stub)
|
||||
return NULL;
|
||||
return stub->dp;
|
||||
return hints_find(hints, &rootlab, qclass, nolock);
|
||||
}
|
||||
|
||||
struct iter_hints_stub*
|
||||
hints_lookup_stub(struct iter_hints* hints, uint8_t* qname,
|
||||
uint16_t qclass, struct delegpt* cache_dp)
|
||||
hints_lookup_stub(struct iter_hints* hints, uint8_t* qname,
|
||||
uint16_t qclass, struct delegpt* cache_dp, int nolock)
|
||||
{
|
||||
size_t len;
|
||||
int labs;
|
||||
@@ -486,14 +512,20 @@ hints_lookup_stub(struct iter_hints* hints, uint8_t* qname,
|
||||
|
||||
/* first lookup the stub */
|
||||
labs = dname_count_size_labels(qname, &len);
|
||||
/* lock_() calls are macros that could be nothing, surround in {} */
|
||||
if(!nolock) { lock_rw_rdlock(&hints->lock); }
|
||||
r = (struct iter_hints_stub*)name_tree_lookup(&hints->tree, qname,
|
||||
len, labs, qclass);
|
||||
if(!r) return NULL;
|
||||
if(!r) {
|
||||
if(!nolock) { lock_rw_unlock(&hints->lock); }
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/* If there is no cache (root prime situation) */
|
||||
if(cache_dp == NULL) {
|
||||
if(r->dp->namelabs != 1)
|
||||
return r; /* no cache dp, use any non-root stub */
|
||||
if(!nolock) { lock_rw_unlock(&hints->lock); }
|
||||
return NULL;
|
||||
}
|
||||
|
||||
@@ -510,12 +542,18 @@ hints_lookup_stub(struct iter_hints* hints, uint8_t* qname,
|
||||
if(dname_strict_subdomain(r->dp->name, r->dp->namelabs,
|
||||
cache_dp->name, cache_dp->namelabs))
|
||||
return r; /* need to prime this stub */
|
||||
if(!nolock) { lock_rw_unlock(&hints->lock); }
|
||||
return NULL;
|
||||
}
|
||||
|
||||
int hints_next_root(struct iter_hints* hints, uint16_t* qclass)
|
||||
int hints_next_root(struct iter_hints* hints, uint16_t* qclass, int nolock)
|
||||
{
|
||||
return name_tree_next_root(&hints->tree, qclass);
|
||||
int ret;
|
||||
/* lock_() calls are macros that could be nothing, surround in {} */
|
||||
if(!nolock) { lock_rw_rdlock(&hints->lock); }
|
||||
ret = name_tree_next_root(&hints->tree, qclass);
|
||||
if(!nolock) { lock_rw_unlock(&hints->lock); }
|
||||
return ret;
|
||||
}
|
||||
|
||||
size_t
|
||||
@@ -524,40 +562,52 @@ hints_get_mem(struct iter_hints* hints)
|
||||
size_t s;
|
||||
struct iter_hints_stub* p;
|
||||
if(!hints) return 0;
|
||||
lock_rw_rdlock(&hints->lock);
|
||||
s = sizeof(*hints);
|
||||
RBTREE_FOR(p, struct iter_hints_stub*, &hints->tree) {
|
||||
s += sizeof(*p) + delegpt_get_mem(p->dp);
|
||||
}
|
||||
lock_rw_unlock(&hints->lock);
|
||||
return s;
|
||||
}
|
||||
|
||||
int
|
||||
hints_add_stub(struct iter_hints* hints, uint16_t c, struct delegpt* dp,
|
||||
int noprime)
|
||||
int noprime, int nolock)
|
||||
{
|
||||
struct iter_hints_stub *z;
|
||||
/* lock_() calls are macros that could be nothing, surround in {} */
|
||||
if(!nolock) { lock_rw_wrlock(&hints->lock); }
|
||||
if((z=(struct iter_hints_stub*)name_tree_find(&hints->tree,
|
||||
dp->name, dp->namelen, dp->namelabs, c)) != NULL) {
|
||||
(void)rbtree_delete(&hints->tree, &z->node);
|
||||
hints_stub_free(z);
|
||||
}
|
||||
if(!hints_insert(hints, c, dp, noprime))
|
||||
if(!hints_insert(hints, c, dp, noprime)) {
|
||||
if(!nolock) { lock_rw_unlock(&hints->lock); }
|
||||
return 0;
|
||||
}
|
||||
name_tree_init_parents(&hints->tree);
|
||||
if(!nolock) { lock_rw_unlock(&hints->lock); }
|
||||
return 1;
|
||||
}
|
||||
|
||||
void
|
||||
hints_delete_stub(struct iter_hints* hints, uint16_t c, uint8_t* nm)
|
||||
hints_delete_stub(struct iter_hints* hints, uint16_t c, uint8_t* nm,
|
||||
int nolock)
|
||||
{
|
||||
struct iter_hints_stub *z;
|
||||
size_t len;
|
||||
int labs = dname_count_size_labels(nm, &len);
|
||||
/* lock_() calls are macros that could be nothing, surround in {} */
|
||||
if(!nolock) { lock_rw_wrlock(&hints->lock); }
|
||||
if(!(z=(struct iter_hints_stub*)name_tree_find(&hints->tree,
|
||||
nm, len, labs, c)))
|
||||
nm, len, labs, c))) {
|
||||
if(!nolock) { lock_rw_unlock(&hints->lock); }
|
||||
return; /* nothing to do */
|
||||
}
|
||||
(void)rbtree_delete(&hints->tree, &z->node);
|
||||
hints_stub_free(z);
|
||||
name_tree_init_parents(&hints->tree);
|
||||
if(!nolock) { lock_rw_unlock(&hints->lock); }
|
||||
}
|
||||
|
||||
|
||||
+47
-7
@@ -43,6 +43,7 @@
|
||||
#ifndef ITERATOR_ITER_HINTS_H
|
||||
#define ITERATOR_ITER_HINTS_H
|
||||
#include "util/storage/dnstree.h"
|
||||
#include "util/locks.h"
|
||||
struct iter_env;
|
||||
struct config_file;
|
||||
struct delegpt;
|
||||
@@ -51,6 +52,10 @@ struct delegpt;
|
||||
* Iterator hints structure
|
||||
*/
|
||||
struct iter_hints {
|
||||
/** lock on the forwards tree.
|
||||
* When grabbing both this lock and the anchors.lock, this lock
|
||||
* is grabbed first. */
|
||||
lock_rw_type lock;
|
||||
/**
|
||||
* Hints are stored in this tree. Sort order is specially chosen.
|
||||
* first sorted on qclass. Then on dname in nsec-like order, so that
|
||||
@@ -95,42 +100,70 @@ void hints_delete(struct iter_hints* hints);
|
||||
int hints_apply_cfg(struct iter_hints* hints, struct config_file* cfg);
|
||||
|
||||
/**
|
||||
* Find root hints for the given class.
|
||||
* Find hints for the given class.
|
||||
* The return value is contents of the hints structure.
|
||||
* Caller should lock and unlock a readlock on the hints structure if nolock
|
||||
* is set.
|
||||
* Otherwise caller should unlock the readlock on the hints structure if a
|
||||
* value was returned.
|
||||
* @param hints: hint storage.
|
||||
* @param qname: the qname that generated the delegation point.
|
||||
* @param qclass: class for which root hints are requested. host order.
|
||||
* @param nolock: Skip locking, locking is handled by the caller.
|
||||
* @return: NULL if no hints, or a ptr to stored hints.
|
||||
*/
|
||||
struct delegpt* hints_lookup_root(struct iter_hints* hints, uint16_t qclass);
|
||||
struct delegpt* hints_find(struct iter_hints* hints, uint8_t* qname,
|
||||
uint16_t qclass, int nolock);
|
||||
|
||||
/**
|
||||
* Same as hints_lookup, but for the root only.
|
||||
* @param hints: hint storage.
|
||||
* @param qclass: class for which root hints are requested. host order.
|
||||
* @param nolock: Skip locking, locking is handled by the caller.
|
||||
* @return: NULL if no hints, or a ptr to stored hints.
|
||||
*/
|
||||
struct delegpt* hints_find_root(struct iter_hints* hints,
|
||||
uint16_t qclass, int nolock);
|
||||
|
||||
/**
|
||||
* Find next root hints (to cycle through all root hints).
|
||||
* Handles its own locking unless nolock is set. In that case the caller
|
||||
* should lock and unlock a readlock on the hints structure.
|
||||
* @param hints: hint storage
|
||||
* @param qclass: class for which root hints are sought.
|
||||
* 0 means give the first available root hints class.
|
||||
* x means, give class x or a higher class if any.
|
||||
* returns the found class in this variable.
|
||||
* @param nolock: Skip locking, locking is handled by the caller.
|
||||
* @return true if a root hint class is found.
|
||||
* false if not root hint class is found (qclass may have been changed).
|
||||
*/
|
||||
int hints_next_root(struct iter_hints* hints, uint16_t* qclass);
|
||||
int hints_next_root(struct iter_hints* hints, uint16_t* qclass, int nolock);
|
||||
|
||||
/**
|
||||
* Given a qname/qclass combination, and the delegation point from the cache
|
||||
* for this qname/qclass, determine if this combination indicates that a
|
||||
* stub hint exists and must be primed.
|
||||
* The return value is contents of the hints structure.
|
||||
* Caller should lock and unlock a readlock on the hints structure if nolock
|
||||
* is set.
|
||||
* Otherwise caller should unlock the readlock on the hints structure if a
|
||||
* value was returned.
|
||||
*
|
||||
* @param hints: hint storage.
|
||||
* @param qname: The qname that generated the delegation point.
|
||||
* @param qclass: The qclass that generated the delegation point.
|
||||
* @param dp: The cache generated delegation point.
|
||||
* @param nolock: Skip locking, locking is handled by the caller.
|
||||
* @return: A priming delegation point if there is a stub hint that must
|
||||
* be primed, otherwise null.
|
||||
*/
|
||||
struct iter_hints_stub* hints_lookup_stub(struct iter_hints* hints,
|
||||
uint8_t* qname, uint16_t qclass, struct delegpt* dp);
|
||||
struct iter_hints_stub* hints_lookup_stub(struct iter_hints* hints,
|
||||
uint8_t* qname, uint16_t qclass, struct delegpt* dp, int nolock);
|
||||
|
||||
/**
|
||||
* Get memory in use by hints
|
||||
* Locks and unlocks the structure.
|
||||
* @param hints: hint storage.
|
||||
* @return bytes in use
|
||||
*/
|
||||
@@ -139,23 +172,30 @@ size_t hints_get_mem(struct iter_hints* hints);
|
||||
/**
|
||||
* Add stub to hints structure. For external use since it recalcs
|
||||
* the tree parents.
|
||||
* Handles its own locking unless nolock is set. In that case the caller
|
||||
* should lock and unlock a writelock on the hints structure.
|
||||
* @param hints: the hints data structure
|
||||
* @param c: class of zone
|
||||
* @param dp: delegation point with name and target nameservers for new
|
||||
* hints stub. malloced.
|
||||
* @param noprime: set noprime option to true or false on new hint stub.
|
||||
* @param nolock: Skip locking, locking is handled by the caller.
|
||||
* @return false on failure (out of memory);
|
||||
*/
|
||||
int hints_add_stub(struct iter_hints* hints, uint16_t c, struct delegpt* dp,
|
||||
int noprime);
|
||||
int noprime, int nolock);
|
||||
|
||||
/**
|
||||
* Remove stub from hints structure. For external use since it
|
||||
* recalcs the tree parents.
|
||||
* Handles its own locking unless nolock is set. In that case the caller
|
||||
* should lock and unlock a writelock on the hints structure.
|
||||
* @param hints: the hints data structure
|
||||
* @param c: class of stub zone
|
||||
* @param nm: name of stub zone (in uncompressed wireformat).
|
||||
* @param nolock: Skip locking, locking is handled by the caller.
|
||||
*/
|
||||
void hints_delete_stub(struct iter_hints* hints, uint16_t c, uint8_t* nm);
|
||||
void hints_delete_stub(struct iter_hints* hints, uint16_t c,
|
||||
uint8_t* nm, int nolock);
|
||||
|
||||
#endif /* ITERATOR_ITER_HINTS_H */
|
||||
|
||||
+2
-24
@@ -207,28 +207,6 @@ size_t priv_get_mem(struct iter_priv* priv)
|
||||
return sizeof(*priv) + regional_get_mem(priv->region);
|
||||
}
|
||||
|
||||
/** remove RR from msgparse RRset, return true if rrset is entirely bad */
|
||||
static int
|
||||
remove_rr(const char* str, sldns_buffer* pkt, struct rrset_parse* rrset,
|
||||
struct rr_parse* prev, struct rr_parse** rr, struct sockaddr_storage* addr, socklen_t addrlen)
|
||||
{
|
||||
if(verbosity >= VERB_QUERY && rrset->dname_len <= LDNS_MAX_DOMAINLEN && str) {
|
||||
uint8_t buf[LDNS_MAX_DOMAINLEN+1];
|
||||
dname_pkt_copy(pkt, buf, rrset->dname);
|
||||
log_name_addr(VERB_QUERY, str, buf, addr, addrlen);
|
||||
}
|
||||
if(prev)
|
||||
prev->next = (*rr)->next;
|
||||
else rrset->rr_first = (*rr)->next;
|
||||
if(rrset->rr_last == *rr)
|
||||
rrset->rr_last = prev;
|
||||
rrset->rr_count --;
|
||||
rrset->size -= (*rr)->size;
|
||||
/* rr struct still exists, but is unlinked, so that in the for loop
|
||||
* the rr->next works fine to continue. */
|
||||
return rrset->rr_count == 0;
|
||||
}
|
||||
|
||||
int priv_rrset_bad(struct iter_priv* priv, sldns_buffer* pkt,
|
||||
struct rrset_parse* rrset)
|
||||
{
|
||||
@@ -261,7 +239,7 @@ int priv_rrset_bad(struct iter_priv* priv, sldns_buffer* pkt,
|
||||
INET_SIZE);
|
||||
memmove(&addr, &sa, len);
|
||||
if(priv_lookup_addr(priv, &addr, len)) {
|
||||
if(remove_rr("sanitize: removing public name with private address", pkt, rrset, prev, &rr, &addr, len))
|
||||
if(msgparse_rrset_remove_rr("sanitize: removing public name with private address", pkt, rrset, prev, rr, &addr, len))
|
||||
return 1;
|
||||
continue;
|
||||
}
|
||||
@@ -284,7 +262,7 @@ int priv_rrset_bad(struct iter_priv* priv, sldns_buffer* pkt,
|
||||
INET6_SIZE);
|
||||
memmove(&addr, &sa, len);
|
||||
if(priv_lookup_addr(priv, &addr, len)) {
|
||||
if(remove_rr("sanitize: removing public name with private address", pkt, rrset, prev, &rr, &addr, len))
|
||||
if(msgparse_rrset_remove_rr("sanitize: removing public name with private address", pkt, rrset, prev, rr, &addr, len))
|
||||
return 1;
|
||||
continue;
|
||||
}
|
||||
|
||||
@@ -42,6 +42,7 @@
|
||||
#include "config.h"
|
||||
#include "iterator/iter_resptype.h"
|
||||
#include "iterator/iter_delegpt.h"
|
||||
#include "iterator/iterator.h"
|
||||
#include "services/cache/dns.h"
|
||||
#include "util/net_help.h"
|
||||
#include "util/data/dname.h"
|
||||
@@ -105,7 +106,8 @@ response_type_from_cache(struct dns_msg* msg,
|
||||
|
||||
enum response_type
|
||||
response_type_from_server(int rdset,
|
||||
struct dns_msg* msg, struct query_info* request, struct delegpt* dp)
|
||||
struct dns_msg* msg, struct query_info* request, struct delegpt* dp,
|
||||
int* empty_nodata_found)
|
||||
{
|
||||
uint8_t* origzone = (uint8_t*)"\000"; /* the default */
|
||||
struct ub_packed_rrset_key* s;
|
||||
@@ -284,13 +286,22 @@ response_type_from_server(int rdset,
|
||||
|
||||
/* If we've gotten this far, this is NOERROR/NODATA (which could
|
||||
* be an entirely empty message) */
|
||||
/* but ignore entirely empty messages, noerror/nodata has a soa
|
||||
* negative ttl value in the authority section, this makes it try
|
||||
* again at another authority. And turns it from a 5 second empty
|
||||
* message into a 5 second servfail response. */
|
||||
/* For entirely empty messages, try again, at first, then accept
|
||||
* it it happens more. A regular noerror/nodata response has a soa
|
||||
* negative ttl value in the authority section. This makes it try
|
||||
* again at another authority. And decides between storing a 5 second
|
||||
* empty message or a 5 second servfail response. */
|
||||
if(msg->rep->an_numrrsets == 0 && msg->rep->ns_numrrsets == 0 &&
|
||||
msg->rep->ar_numrrsets == 0)
|
||||
return RESPONSE_TYPE_THROWAWAY;
|
||||
msg->rep->ar_numrrsets == 0) {
|
||||
if(empty_nodata_found) {
|
||||
/* detect as throwaway at first, but accept later. */
|
||||
(*empty_nodata_found)++;
|
||||
if(*empty_nodata_found < EMPTY_NODATA_RETRY_COUNT)
|
||||
return RESPONSE_TYPE_THROWAWAY;
|
||||
return RESPONSE_TYPE_ANSWER;
|
||||
}
|
||||
return RESPONSE_TYPE_ANSWER;
|
||||
}
|
||||
/* check if recursive answer; saying it has empty cache */
|
||||
if( (msg->rep->flags&BIT_RA) && !(msg->rep->flags&BIT_AA) && !rdset)
|
||||
return RESPONSE_TYPE_REC_LAME;
|
||||
|
||||
@@ -119,9 +119,11 @@ enum response_type response_type_from_cache(struct dns_msg* msg,
|
||||
* @param request: the request that generated the response.
|
||||
* @param dp: The delegation point that was being queried
|
||||
* when the response was returned.
|
||||
* @param empty_nodata_found: flag to keep track of empty nodata detection.
|
||||
* @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);
|
||||
struct dns_msg* msg, struct query_info* request, struct delegpt* dp,
|
||||
int* empty_nodata_found);
|
||||
|
||||
#endif /* ITERATOR_ITER_RESPTYPE_H */
|
||||
|
||||
+66
-4
@@ -283,7 +283,8 @@ synth_cname_rrset(uint8_t** sname, size_t* snamelen, uint8_t* alias,
|
||||
sizeof(uint32_t)+sizeof(uint16_t)+aliaslen);
|
||||
if(!cn->rr_first->ttl_data)
|
||||
return NULL;
|
||||
sldns_write_uint32(cn->rr_first->ttl_data, 0); /* TTL = 0 */
|
||||
memmove(cn->rr_first->ttl_data, rrset->rr_first->ttl_data,
|
||||
sizeof(uint32_t)); /* RFC6672: synth CNAME TTL == DNAME 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;
|
||||
@@ -716,6 +717,56 @@ static int sanitize_nsec_is_overreach(sldns_buffer* pkt,
|
||||
return 0;
|
||||
}
|
||||
|
||||
/** Remove individual RRs, if the length is wrong. Returns true if the RRset
|
||||
* has been removed. */
|
||||
static int
|
||||
scrub_sanitize_rr_length(sldns_buffer* pkt, struct msg_parse* msg,
|
||||
struct rrset_parse* prev, struct rrset_parse** rrset, int* added_ede,
|
||||
struct module_qstate* qstate)
|
||||
{
|
||||
struct rr_parse* rr, *rr_prev = NULL;
|
||||
for(rr = (*rrset)->rr_first; rr; rr = rr->next) {
|
||||
|
||||
/* Sanity check for length of records
|
||||
* An A record should be 6 bytes only
|
||||
* (2 bytes for length and 4 for IPv4 addr)*/
|
||||
if((*rrset)->type == LDNS_RR_TYPE_A && rr->size != 6 ) {
|
||||
if(!*added_ede) {
|
||||
*added_ede = 1;
|
||||
errinf_ede(qstate, "sanitize: records of inappropriate length have been removed.",
|
||||
LDNS_EDE_OTHER);
|
||||
}
|
||||
if(msgparse_rrset_remove_rr("sanitize: removing type A RR of inappropriate length:",
|
||||
pkt, *rrset, rr_prev, rr, NULL, 0)) {
|
||||
remove_rrset("sanitize: removing type A RRset of inappropriate length:",
|
||||
pkt, msg, prev, rrset);
|
||||
return 1;
|
||||
}
|
||||
continue;
|
||||
}
|
||||
|
||||
/* Sanity check for length of records
|
||||
* An AAAA record should be 18 bytes only
|
||||
* (2 bytes for length and 16 for IPv6 addr)*/
|
||||
if((*rrset)->type == LDNS_RR_TYPE_AAAA && rr->size != 18 ) {
|
||||
if(!*added_ede) {
|
||||
*added_ede = 1;
|
||||
errinf_ede(qstate, "sanitize: records of inappropriate length have been removed.",
|
||||
LDNS_EDE_OTHER);
|
||||
}
|
||||
if(msgparse_rrset_remove_rr("sanitize: removing type AAAA RR of inappropriate length:",
|
||||
pkt, *rrset, rr_prev, rr, NULL, 0)) {
|
||||
remove_rrset("sanitize: removing type AAAA RRset of inappropriate length:",
|
||||
pkt, msg, prev, rrset);
|
||||
return 1;
|
||||
}
|
||||
continue;
|
||||
}
|
||||
rr_prev = rr;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Given a response event, remove suspect RRsets from the response.
|
||||
* "Suspect" rrsets are potentially poison. Note that this routine expects
|
||||
@@ -728,15 +779,17 @@ static int sanitize_nsec_is_overreach(sldns_buffer* pkt,
|
||||
* @param zonename: name of server zone.
|
||||
* @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.
|
||||
* @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 iter_env* ie, struct module_qstate* qstate)
|
||||
{
|
||||
int del_addi = 0; /* if additional-holding rrsets are deleted, we
|
||||
do not trust the normalized additional-A-AAAA any more */
|
||||
int added_rrlen_ede = 0;
|
||||
struct rrset_parse* rrset, *prev;
|
||||
prev = NULL;
|
||||
rrset = msg->rrset_first;
|
||||
@@ -781,6 +834,14 @@ scrub_sanitize(sldns_buffer* pkt, struct msg_parse* msg,
|
||||
rrset = msg->rrset_first;
|
||||
while(rrset) {
|
||||
|
||||
/* Sanity check for length of records */
|
||||
if(rrset->type == LDNS_RR_TYPE_A ||
|
||||
rrset->type == LDNS_RR_TYPE_AAAA) {
|
||||
if(scrub_sanitize_rr_length(pkt, msg, prev, &rrset,
|
||||
&added_rrlen_ede, qstate))
|
||||
continue;
|
||||
}
|
||||
|
||||
/* remove private addresses */
|
||||
if( (rrset->type == LDNS_RR_TYPE_A ||
|
||||
rrset->type == LDNS_RR_TYPE_AAAA)) {
|
||||
@@ -854,7 +915,8 @@ scrub_sanitize(sldns_buffer* pkt, struct msg_parse* msg,
|
||||
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 iter_env* ie)
|
||||
struct module_env* env, struct module_qstate* qstate,
|
||||
struct iter_env* ie)
|
||||
{
|
||||
/* basic sanity checks */
|
||||
log_nametypeclass(VERB_ALGO, "scrub for", zonename, LDNS_RR_TYPE_NS,
|
||||
@@ -886,7 +948,7 @@ scrub_message(sldns_buffer* pkt, struct msg_parse* msg,
|
||||
if(!scrub_normalize(pkt, msg, qinfo, region, env))
|
||||
return 0;
|
||||
/* delete all out-of-zone information */
|
||||
if(!scrub_sanitize(pkt, msg, qinfo, zonename, env, ie))
|
||||
if(!scrub_sanitize(pkt, msg, qinfo, zonename, env, ie, qstate))
|
||||
return 0;
|
||||
return 1;
|
||||
}
|
||||
|
||||
@@ -48,6 +48,7 @@ struct query_info;
|
||||
struct regional;
|
||||
struct module_env;
|
||||
struct iter_env;
|
||||
struct module_qstate;
|
||||
|
||||
/**
|
||||
* Cleanup the passed dns message.
|
||||
@@ -59,11 +60,13 @@ struct iter_env;
|
||||
* Used to determine out of bailiwick information.
|
||||
* @param regional: where to allocate (new) parts of the message.
|
||||
* @param env: module environment with config settings and cache.
|
||||
* @param qstate: for setting errinf for EDE error messages.
|
||||
* @param ie: iterator module environment data.
|
||||
* @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 iter_env* ie);
|
||||
struct module_env* env, struct module_qstate* qstate,
|
||||
struct iter_env* ie);
|
||||
|
||||
#endif /* ITERATOR_ITER_SCRUB_H */
|
||||
|
||||
+53
-12
@@ -279,9 +279,10 @@ iter_filter_unsuitable(struct iter_env* iter_env, struct module_env* env,
|
||||
name, namelen, qtype, &lame, &dnsseclame, &reclame,
|
||||
&rtt, now)) {
|
||||
log_addr(VERB_ALGO, "servselect", &a->addr, a->addrlen);
|
||||
verbose(VERB_ALGO, " rtt=%d%s%s%s%s", rtt,
|
||||
verbose(VERB_ALGO, " rtt=%d%s%s%s%s%s", rtt,
|
||||
lame?" LAME":"",
|
||||
dnsseclame?" DNSSEC_LAME":"",
|
||||
a->dnsseclame?" ADDR_DNSSEC_LAME":"",
|
||||
reclame?" REC_LAME":"",
|
||||
a->lame?" ADDR_LAME":"");
|
||||
if(lame)
|
||||
@@ -1284,8 +1285,17 @@ iter_get_next_root(struct iter_hints* hints, struct iter_forwards* fwd,
|
||||
uint16_t* c)
|
||||
{
|
||||
uint16_t c1 = *c, c2 = *c;
|
||||
int r1 = hints_next_root(hints, &c1);
|
||||
int r2 = forwards_next_root(fwd, &c2);
|
||||
int r1, r2;
|
||||
int nolock = 1;
|
||||
|
||||
/* prelock both forwards and hints for atomic read. */
|
||||
lock_rw_rdlock(&fwd->lock);
|
||||
lock_rw_rdlock(&hints->lock);
|
||||
r1 = hints_next_root(hints, &c1, nolock);
|
||||
r2 = forwards_next_root(fwd, &c2, nolock);
|
||||
lock_rw_unlock(&fwd->lock);
|
||||
lock_rw_unlock(&hints->lock);
|
||||
|
||||
if(!r1 && !r2) /* got none, end of list */
|
||||
return 0;
|
||||
else if(!r1) /* got one, return that */
|
||||
@@ -1450,15 +1460,21 @@ int iter_dp_cangodown(struct query_info* qinfo, struct delegpt* dp)
|
||||
|
||||
int
|
||||
iter_stub_fwd_no_cache(struct module_qstate *qstate, struct query_info *qinf,
|
||||
uint8_t** retdpname, size_t* retdpnamelen)
|
||||
uint8_t** retdpname, size_t* retdpnamelen, uint8_t* dpname_storage,
|
||||
size_t dpname_storage_len)
|
||||
{
|
||||
struct iter_hints_stub *stub;
|
||||
struct delegpt *dp;
|
||||
int nolock = 1;
|
||||
|
||||
/* Check for stub. */
|
||||
/* Lock both forwards and hints for atomic read. */
|
||||
lock_rw_rdlock(&qstate->env->fwds->lock);
|
||||
lock_rw_rdlock(&qstate->env->hints->lock);
|
||||
stub = hints_lookup_stub(qstate->env->hints, qinf->qname,
|
||||
qinf->qclass, NULL);
|
||||
dp = forwards_lookup(qstate->env->fwds, qinf->qname, qinf->qclass);
|
||||
qinf->qclass, NULL, nolock);
|
||||
dp = forwards_lookup(qstate->env->fwds, qinf->qname, qinf->qclass,
|
||||
nolock);
|
||||
|
||||
/* see if forward or stub is more pertinent */
|
||||
if(stub && stub->dp && dp) {
|
||||
@@ -1472,7 +1488,9 @@ iter_stub_fwd_no_cache(struct module_qstate *qstate, struct query_info *qinf,
|
||||
|
||||
/* check stub */
|
||||
if (stub != NULL && stub->dp != NULL) {
|
||||
if(stub->dp->no_cache) {
|
||||
int stub_no_cache = stub->dp->no_cache;
|
||||
lock_rw_unlock(&qstate->env->fwds->lock);
|
||||
if(stub_no_cache) {
|
||||
char qname[255+1];
|
||||
char dpname[255+1];
|
||||
dname_str(qinf->qname, qname);
|
||||
@@ -1480,15 +1498,27 @@ iter_stub_fwd_no_cache(struct module_qstate *qstate, struct query_info *qinf,
|
||||
verbose(VERB_ALGO, "stub for %s %s has no_cache", qname, dpname);
|
||||
}
|
||||
if(retdpname) {
|
||||
*retdpname = stub->dp->name;
|
||||
if(stub->dp->namelen > dpname_storage_len) {
|
||||
verbose(VERB_ALGO, "no cache stub dpname too long");
|
||||
lock_rw_unlock(&qstate->env->hints->lock);
|
||||
*retdpname = NULL;
|
||||
*retdpnamelen = 0;
|
||||
return stub_no_cache;
|
||||
}
|
||||
memmove(dpname_storage, stub->dp->name,
|
||||
stub->dp->namelen);
|
||||
*retdpname = dpname_storage;
|
||||
*retdpnamelen = stub->dp->namelen;
|
||||
}
|
||||
return (stub->dp->no_cache);
|
||||
lock_rw_unlock(&qstate->env->hints->lock);
|
||||
return stub_no_cache;
|
||||
}
|
||||
|
||||
/* Check for forward. */
|
||||
if (dp) {
|
||||
if(dp->no_cache) {
|
||||
int dp_no_cache = dp->no_cache;
|
||||
lock_rw_unlock(&qstate->env->hints->lock);
|
||||
if(dp_no_cache) {
|
||||
char qname[255+1];
|
||||
char dpname[255+1];
|
||||
dname_str(qinf->qname, qname);
|
||||
@@ -1496,11 +1526,22 @@ iter_stub_fwd_no_cache(struct module_qstate *qstate, struct query_info *qinf,
|
||||
verbose(VERB_ALGO, "forward for %s %s has no_cache", qname, dpname);
|
||||
}
|
||||
if(retdpname) {
|
||||
*retdpname = dp->name;
|
||||
if(dp->namelen > dpname_storage_len) {
|
||||
verbose(VERB_ALGO, "no cache dpname too long");
|
||||
lock_rw_unlock(&qstate->env->fwds->lock);
|
||||
*retdpname = NULL;
|
||||
*retdpnamelen = 0;
|
||||
return dp_no_cache;
|
||||
}
|
||||
memmove(dpname_storage, dp->name, dp->namelen);
|
||||
*retdpname = dpname_storage;
|
||||
*retdpnamelen = dp->namelen;
|
||||
}
|
||||
return (dp->no_cache);
|
||||
lock_rw_unlock(&qstate->env->fwds->lock);
|
||||
return dp_no_cache;
|
||||
}
|
||||
lock_rw_unlock(&qstate->env->fwds->lock);
|
||||
lock_rw_unlock(&qstate->env->hints->lock);
|
||||
if(retdpname) {
|
||||
*retdpname = NULL;
|
||||
*retdpnamelen = 0;
|
||||
|
||||
@@ -407,10 +407,14 @@ int iter_dp_cangodown(struct query_info* qinfo, struct delegpt* dp);
|
||||
* Used for NXDOMAIN checks, above that it is an nxdomain from a
|
||||
* different server and zone. You can pass NULL to not get it.
|
||||
* @param retdpnamelen: returns the length of the dpname.
|
||||
* @param dpname_storage: this is where the dpname buf is stored, if any.
|
||||
* So that caller can manage the buffer.
|
||||
* @param dpname_storage_len: size of dpname_storage buffer.
|
||||
* @return true if no_cache is set in stub or fwd.
|
||||
*/
|
||||
int iter_stub_fwd_no_cache(struct module_qstate *qstate,
|
||||
struct query_info *qinf, uint8_t** retdpname, size_t* retdpnamelen);
|
||||
struct query_info *qinf, uint8_t** retdpname, size_t* retdpnamelen,
|
||||
uint8_t* dpname_storage, size_t dpname_storage_len);
|
||||
|
||||
/**
|
||||
* Set support for IP4 and IP6 depending on outgoing interfaces
|
||||
|
||||
+300
-93
@@ -52,6 +52,7 @@
|
||||
#include "iterator/iter_priv.h"
|
||||
#include "validator/val_neg.h"
|
||||
#include "services/cache/dns.h"
|
||||
#include "services/cache/rrset.h"
|
||||
#include "services/cache/infra.h"
|
||||
#include "services/authzone.h"
|
||||
#include "util/module.h"
|
||||
@@ -678,30 +679,40 @@ errinf_reply(struct module_qstate* qstate, struct iter_qstate* iq)
|
||||
|
||||
/** see if last resort is possible - does config allow queries to parent */
|
||||
static int
|
||||
can_have_last_resort(struct module_env* env, uint8_t* nm, size_t nmlen,
|
||||
uint16_t qclass, struct delegpt** retdp)
|
||||
can_have_last_resort(struct module_env* env, uint8_t* nm, size_t ATTR_UNUSED(nmlen),
|
||||
uint16_t qclass, int* have_dp, struct delegpt** retdp,
|
||||
struct regional* region)
|
||||
{
|
||||
struct delegpt* fwddp;
|
||||
struct iter_hints_stub* stub;
|
||||
int labs = dname_count_labels(nm);
|
||||
struct delegpt* dp = NULL;
|
||||
int nolock = 0;
|
||||
/* do not process a last resort (the parent side) if a stub
|
||||
* or forward is configured, because we do not want to go 'above'
|
||||
* the configured servers */
|
||||
if(!dname_is_root(nm) && (stub = (struct iter_hints_stub*)
|
||||
name_tree_find(&env->hints->tree, nm, nmlen, labs, qclass)) &&
|
||||
if(!dname_is_root(nm) &&
|
||||
(dp = hints_find(env->hints, nm, qclass, nolock)) &&
|
||||
/* has_parent side is turned off for stub_first, where we
|
||||
* are allowed to go to the parent */
|
||||
stub->dp->has_parent_side_NS) {
|
||||
if(retdp) *retdp = stub->dp;
|
||||
dp->has_parent_side_NS) {
|
||||
if(retdp) *retdp = delegpt_copy(dp, region);
|
||||
lock_rw_unlock(&env->hints->lock);
|
||||
if(have_dp) *have_dp = 1;
|
||||
return 0;
|
||||
}
|
||||
if((fwddp = forwards_find(env->fwds, nm, qclass)) &&
|
||||
if(dp) {
|
||||
lock_rw_unlock(&env->hints->lock);
|
||||
dp = NULL;
|
||||
}
|
||||
if((dp = forwards_find(env->fwds, nm, qclass, nolock)) &&
|
||||
/* has_parent_side is turned off for forward_first, where
|
||||
* we are allowed to go to the parent */
|
||||
fwddp->has_parent_side_NS) {
|
||||
if(retdp) *retdp = fwddp;
|
||||
dp->has_parent_side_NS) {
|
||||
if(retdp) *retdp = delegpt_copy(dp, region);
|
||||
lock_rw_unlock(&env->fwds->lock);
|
||||
if(have_dp) *have_dp = 1;
|
||||
return 0;
|
||||
}
|
||||
/* lock_() calls are macros that could be nothing, surround in {} */
|
||||
if(dp) { lock_rw_unlock(&env->fwds->lock); }
|
||||
return 1;
|
||||
}
|
||||
|
||||
@@ -877,10 +888,11 @@ prime_root(struct module_qstate* qstate, struct iter_qstate* iq, int id,
|
||||
{
|
||||
struct delegpt* dp;
|
||||
struct module_qstate* subq;
|
||||
int nolock = 0;
|
||||
verbose(VERB_DETAIL, "priming . %s NS",
|
||||
sldns_lookup_by_id(sldns_rr_classes, (int)qclass)?
|
||||
sldns_lookup_by_id(sldns_rr_classes, (int)qclass)->name:"??");
|
||||
dp = hints_lookup_root(qstate->env->hints, qclass);
|
||||
dp = hints_find_root(qstate->env->hints, qclass, nolock);
|
||||
if(!dp) {
|
||||
verbose(VERB_ALGO, "Cannot prime due to lack of hints");
|
||||
return 0;
|
||||
@@ -890,6 +902,7 @@ prime_root(struct module_qstate* qstate, struct iter_qstate* iq, int id,
|
||||
if(!generate_sub_request((uint8_t*)"\000", 1, LDNS_RR_TYPE_NS,
|
||||
qclass, qstate, id, iq, QUERYTARGETS_STATE, PRIME_RESP_STATE,
|
||||
&subq, 0, 0)) {
|
||||
lock_rw_unlock(&qstate->env->hints->lock);
|
||||
verbose(VERB_ALGO, "could not prime root");
|
||||
return 0;
|
||||
}
|
||||
@@ -900,6 +913,7 @@ prime_root(struct module_qstate* qstate, struct iter_qstate* iq, int id,
|
||||
* copy dp, it is now part of the root prime query.
|
||||
* dp was part of in the fixed hints structure. */
|
||||
subiq->dp = delegpt_copy(dp, subq->region);
|
||||
lock_rw_unlock(&qstate->env->hints->lock);
|
||||
if(!subiq->dp) {
|
||||
log_err("out of memory priming root, copydp");
|
||||
fptr_ok(fptr_whitelist_modenv_kill_sub(
|
||||
@@ -911,6 +925,8 @@ prime_root(struct module_qstate* qstate, struct iter_qstate* iq, int id,
|
||||
subiq->num_target_queries = 0;
|
||||
subiq->dnssec_expected = iter_indicates_dnssec(
|
||||
qstate->env, subiq->dp, NULL, subq->qinfo.qclass);
|
||||
} else {
|
||||
lock_rw_unlock(&qstate->env->hints->lock);
|
||||
}
|
||||
|
||||
/* this module stops, our submodule starts, and does the query. */
|
||||
@@ -941,18 +957,21 @@ prime_stub(struct module_qstate* qstate, struct iter_qstate* iq, int id,
|
||||
struct iter_hints_stub* stub;
|
||||
struct delegpt* stub_dp;
|
||||
struct module_qstate* subq;
|
||||
int nolock = 0;
|
||||
|
||||
if(!qname) return 0;
|
||||
stub = hints_lookup_stub(qstate->env->hints, qname, qclass, iq->dp);
|
||||
stub = hints_lookup_stub(qstate->env->hints, qname, qclass, iq->dp,
|
||||
nolock);
|
||||
/* The stub (if there is one) does not need priming. */
|
||||
if(!stub)
|
||||
return 0;
|
||||
if(!stub) return 0;
|
||||
stub_dp = stub->dp;
|
||||
/* if we have an auth_zone dp, and stub is equal, don't prime stub
|
||||
* yet, unless we want to fallback and avoid the auth_zone */
|
||||
if(!iq->auth_zone_avoid && iq->dp && iq->dp->auth_dp &&
|
||||
query_dname_compare(iq->dp->name, stub_dp->name) == 0)
|
||||
query_dname_compare(iq->dp->name, stub_dp->name) == 0) {
|
||||
lock_rw_unlock(&qstate->env->hints->lock);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* is it a noprime stub (always use) */
|
||||
if(stub->noprime) {
|
||||
@@ -961,13 +980,14 @@ prime_stub(struct module_qstate* qstate, struct iter_qstate* iq, int id,
|
||||
/* copy the dp out of the fixed hints structure, so that
|
||||
* it can be changed when servicing this query */
|
||||
iq->dp = delegpt_copy(stub_dp, qstate->region);
|
||||
lock_rw_unlock(&qstate->env->hints->lock);
|
||||
if(!iq->dp) {
|
||||
log_err("out of memory priming stub");
|
||||
errinf(qstate, "malloc failure, priming stub");
|
||||
(void)error_response(qstate, id, LDNS_RCODE_SERVFAIL);
|
||||
return 1; /* return 1 to make module stop, with error */
|
||||
}
|
||||
log_nametypeclass(VERB_DETAIL, "use stub", stub_dp->name,
|
||||
log_nametypeclass(VERB_DETAIL, "use stub", iq->dp->name,
|
||||
LDNS_RR_TYPE_NS, qclass);
|
||||
return r;
|
||||
}
|
||||
@@ -981,6 +1001,7 @@ prime_stub(struct module_qstate* qstate, struct iter_qstate* iq, int id,
|
||||
if(!generate_sub_request(stub_dp->name, stub_dp->namelen,
|
||||
LDNS_RR_TYPE_NS, qclass, qstate, id, iq,
|
||||
QUERYTARGETS_STATE, PRIME_RESP_STATE, &subq, 0, 0)) {
|
||||
lock_rw_unlock(&qstate->env->hints->lock);
|
||||
verbose(VERB_ALGO, "could not prime stub");
|
||||
errinf(qstate, "could not generate lookup for stub prime");
|
||||
(void)error_response(qstate, id, LDNS_RCODE_SERVFAIL);
|
||||
@@ -993,6 +1014,7 @@ prime_stub(struct module_qstate* qstate, struct iter_qstate* iq, int id,
|
||||
/* Set the initial delegation point to the hint. */
|
||||
/* make copy to avoid use of stub dp by different qs/threads */
|
||||
subiq->dp = delegpt_copy(stub_dp, subq->region);
|
||||
lock_rw_unlock(&qstate->env->hints->lock);
|
||||
if(!subiq->dp) {
|
||||
log_err("out of memory priming stub, copydp");
|
||||
fptr_ok(fptr_whitelist_modenv_kill_sub(
|
||||
@@ -1009,6 +1031,8 @@ prime_stub(struct module_qstate* qstate, struct iter_qstate* iq, int id,
|
||||
subiq->wait_priming_stub = 1;
|
||||
subiq->dnssec_expected = iter_indicates_dnssec(
|
||||
qstate->env, subiq->dp, NULL, subq->qinfo.qclass);
|
||||
} else {
|
||||
lock_rw_unlock(&qstate->env->hints->lock);
|
||||
}
|
||||
|
||||
/* this module stops, our submodule starts, and does the query. */
|
||||
@@ -1181,7 +1205,7 @@ generate_ns_check(struct module_qstate* qstate, struct iter_qstate* iq, int id)
|
||||
if(iq->depth == ie->max_dependency_depth)
|
||||
return;
|
||||
if(!can_have_last_resort(qstate->env, iq->dp->name, iq->dp->namelen,
|
||||
iq->qchase.qclass, NULL))
|
||||
iq->qchase.qclass, NULL, NULL, NULL))
|
||||
return;
|
||||
/* is this query the same as the nscheck? */
|
||||
if(qstate->qinfo.qtype == LDNS_RR_TYPE_NS &&
|
||||
@@ -1294,6 +1318,7 @@ forward_request(struct module_qstate* qstate, struct iter_qstate* iq)
|
||||
struct delegpt* dp;
|
||||
uint8_t* delname = iq->qchase.qname;
|
||||
size_t delnamelen = iq->qchase.qname_len;
|
||||
int nolock = 0;
|
||||
if(iq->refetch_glue && iq->dp) {
|
||||
delname = iq->dp->name;
|
||||
delnamelen = iq->dp->namelen;
|
||||
@@ -1302,12 +1327,13 @@ forward_request(struct module_qstate* qstate, struct iter_qstate* iq)
|
||||
if( (iq->qchase.qtype == LDNS_RR_TYPE_DS || iq->refetch_glue)
|
||||
&& !dname_is_root(iq->qchase.qname))
|
||||
dname_remove_label(&delname, &delnamelen);
|
||||
dp = forwards_lookup(qstate->env->fwds, delname, iq->qchase.qclass);
|
||||
if(!dp)
|
||||
return 0;
|
||||
dp = forwards_lookup(qstate->env->fwds, delname, iq->qchase.qclass,
|
||||
nolock);
|
||||
if(!dp) return 0;
|
||||
/* send recursion desired to forward addr */
|
||||
iq->chase_flags |= BIT_RD;
|
||||
iq->dp = delegpt_copy(dp, qstate->region);
|
||||
lock_rw_unlock(&qstate->env->fwds->lock);
|
||||
/* iq->dp checked by caller */
|
||||
verbose(VERB_ALGO, "forwarding request");
|
||||
return 1;
|
||||
@@ -1335,6 +1361,7 @@ static int
|
||||
processInitRequest(struct module_qstate* qstate, struct iter_qstate* iq,
|
||||
struct iter_env* ie, int id)
|
||||
{
|
||||
uint8_t dpname_storage[LDNS_MAX_DOMAINLEN+1];
|
||||
uint8_t* delname, *dpname=NULL;
|
||||
size_t delnamelen, dpnamelen=0;
|
||||
struct dns_msg* msg = NULL;
|
||||
@@ -1351,7 +1378,7 @@ processInitRequest(struct module_qstate* qstate, struct iter_qstate* iq,
|
||||
"restarts (eg. indirections)");
|
||||
if(iq->qchase.qname)
|
||||
errinf_dname(qstate, "stop at", iq->qchase.qname);
|
||||
return error_response(qstate, id, LDNS_RCODE_SERVFAIL);
|
||||
return error_response_cache(qstate, id, LDNS_RCODE_SERVFAIL);
|
||||
}
|
||||
|
||||
/* We enforce a maximum recursion/dependency depth -- in general,
|
||||
@@ -1381,7 +1408,7 @@ processInitRequest(struct module_qstate* qstate, struct iter_qstate* iq,
|
||||
if (iq->refetch_glue &&
|
||||
iq->dp &&
|
||||
!can_have_last_resort(qstate->env, iq->dp->name,
|
||||
iq->dp->namelen, iq->qchase.qclass, NULL)) {
|
||||
iq->dp->namelen, iq->qchase.qclass, NULL, NULL, NULL)) {
|
||||
iq->refetch_glue = 0;
|
||||
}
|
||||
|
||||
@@ -1389,8 +1416,61 @@ processInitRequest(struct module_qstate* qstate, struct iter_qstate* iq,
|
||||
|
||||
/* This either results in a query restart (CNAME cache response), a
|
||||
* terminating response (ANSWER), or a cache miss (null). */
|
||||
|
||||
if (iter_stub_fwd_no_cache(qstate, &iq->qchase, &dpname, &dpnamelen)) {
|
||||
|
||||
/* Check RPZ for override */
|
||||
if(qstate->env->auth_zones) {
|
||||
/* apply rpz qname triggers, like after cname */
|
||||
struct dns_msg* forged_response =
|
||||
rpz_callback_from_iterator_cname(qstate, iq);
|
||||
if(forged_response) {
|
||||
uint8_t* sname = 0;
|
||||
size_t slen = 0;
|
||||
int count = 0;
|
||||
while(forged_response && reply_find_rrset_section_an(
|
||||
forged_response->rep, iq->qchase.qname,
|
||||
iq->qchase.qname_len, LDNS_RR_TYPE_CNAME,
|
||||
iq->qchase.qclass) &&
|
||||
iq->qchase.qtype != LDNS_RR_TYPE_CNAME &&
|
||||
count++ < ie->max_query_restarts) {
|
||||
/* another cname to follow */
|
||||
if(!handle_cname_response(qstate, iq, forged_response,
|
||||
&sname, &slen)) {
|
||||
errinf(qstate, "malloc failure, CNAME info");
|
||||
return error_response(qstate, id, LDNS_RCODE_SERVFAIL);
|
||||
}
|
||||
iq->qchase.qname = sname;
|
||||
iq->qchase.qname_len = slen;
|
||||
forged_response =
|
||||
rpz_callback_from_iterator_cname(qstate, iq);
|
||||
}
|
||||
if(forged_response != NULL) {
|
||||
qstate->ext_state[id] = module_finished;
|
||||
qstate->return_rcode = LDNS_RCODE_NOERROR;
|
||||
qstate->return_msg = forged_response;
|
||||
iq->response = forged_response;
|
||||
next_state(iq, FINISHED_STATE);
|
||||
if(!iter_prepend(iq, qstate->return_msg, qstate->region)) {
|
||||
log_err("rpz: after cached cname, prepend rrsets: out of memory");
|
||||
return error_response(qstate, id, LDNS_RCODE_SERVFAIL);
|
||||
}
|
||||
qstate->return_msg->qinfo = qstate->qinfo;
|
||||
return 0;
|
||||
}
|
||||
/* Follow the CNAME response */
|
||||
iq->dp = NULL;
|
||||
iq->refetch_glue = 0;
|
||||
iq->query_restart_count++;
|
||||
iq->sent_count = 0;
|
||||
iq->dp_target_count = 0;
|
||||
sock_list_insert(&qstate->reply_origin, NULL, 0, qstate->region);
|
||||
if(qstate->env->cfg->qname_minimisation)
|
||||
iq->minimisation_state = INIT_MINIMISE_STATE;
|
||||
return next_state(iq, INIT_REQUEST_STATE);
|
||||
}
|
||||
}
|
||||
|
||||
if (iter_stub_fwd_no_cache(qstate, &iq->qchase, &dpname, &dpnamelen,
|
||||
dpname_storage, sizeof(dpname_storage))) {
|
||||
/* Asked to not query cache. */
|
||||
verbose(VERB_ALGO, "no-cache set, going to the network");
|
||||
qstate->no_cache_lookup = 1;
|
||||
@@ -1461,7 +1541,6 @@ processInitRequest(struct module_qstate* qstate, struct iter_qstate* iq,
|
||||
iq->minimisation_state = INIT_MINIMISE_STATE;
|
||||
return next_state(iq, INIT_REQUEST_STATE);
|
||||
}
|
||||
|
||||
/* if from cache, NULL, else insert 'cache IP' len=0 */
|
||||
if(qstate->reply_origin)
|
||||
sock_list_insert(&qstate->reply_origin, NULL, 0, qstate->region);
|
||||
@@ -1522,7 +1601,7 @@ processInitRequest(struct module_qstate* qstate, struct iter_qstate* iq,
|
||||
}
|
||||
if(iq->qchase.qtype == LDNS_RR_TYPE_DS || iq->refetch_glue ||
|
||||
(iq->qchase.qtype == LDNS_RR_TYPE_NS && qstate->prefetch_leeway
|
||||
&& can_have_last_resort(qstate->env, delname, delnamelen, iq->qchase.qclass, NULL))) {
|
||||
&& can_have_last_resort(qstate->env, delname, delnamelen, iq->qchase.qclass, NULL, NULL, NULL))) {
|
||||
/* remove first label from delname, root goes to hints,
|
||||
* but only to fetch glue, not for qtype=DS. */
|
||||
/* also when prefetching an NS record, fetch it again from
|
||||
@@ -1551,6 +1630,7 @@ processInitRequest(struct module_qstate* qstate, struct iter_qstate* iq,
|
||||
* root priming situation. */
|
||||
if(iq->dp == NULL) {
|
||||
int r;
|
||||
int nolock = 0;
|
||||
/* if under auth zone, no prime needed */
|
||||
if(!auth_zone_delegpt(qstate, iq, delname, delnamelen))
|
||||
return error_response(qstate, id,
|
||||
@@ -1564,19 +1644,21 @@ processInitRequest(struct module_qstate* qstate, struct iter_qstate* iq,
|
||||
break; /* got noprime-stub-zone, continue */
|
||||
else if(r)
|
||||
return 0; /* stub prime request made */
|
||||
if(forwards_lookup_root(qstate->env->fwds,
|
||||
iq->qchase.qclass)) {
|
||||
if(forwards_lookup_root(qstate->env->fwds,
|
||||
iq->qchase.qclass, nolock)) {
|
||||
lock_rw_unlock(&qstate->env->fwds->lock);
|
||||
/* forward zone root, no root prime needed */
|
||||
/* fill in some dp - safety belt */
|
||||
iq->dp = hints_lookup_root(qstate->env->hints,
|
||||
iq->qchase.qclass);
|
||||
iq->dp = hints_find_root(qstate->env->hints,
|
||||
iq->qchase.qclass, nolock);
|
||||
if(!iq->dp) {
|
||||
log_err("internal error: no hints dp");
|
||||
errinf(qstate, "no hints for this class");
|
||||
return error_response(qstate, id,
|
||||
return error_response_cache(qstate, id,
|
||||
LDNS_RCODE_SERVFAIL);
|
||||
}
|
||||
iq->dp = delegpt_copy(iq->dp, qstate->region);
|
||||
lock_rw_unlock(&qstate->env->hints->lock);
|
||||
if(!iq->dp) {
|
||||
log_err("out of memory in safety belt");
|
||||
errinf(qstate, "malloc failure, in safety belt");
|
||||
@@ -1616,15 +1698,13 @@ processInitRequest(struct module_qstate* qstate, struct iter_qstate* iq,
|
||||
if(iter_dp_is_useless(&qstate->qinfo, qstate->query_flags,
|
||||
iq->dp, ie->supports_ipv4, ie->supports_ipv6,
|
||||
ie->use_nat64)) {
|
||||
struct delegpt* retdp = NULL;
|
||||
if(!can_have_last_resort(qstate->env, iq->dp->name, iq->dp->namelen, iq->qchase.qclass, &retdp)) {
|
||||
if(retdp) {
|
||||
int have_dp = 0;
|
||||
if(!can_have_last_resort(qstate->env, iq->dp->name, iq->dp->namelen, iq->qchase.qclass, &have_dp, &iq->dp, qstate->region)) {
|
||||
if(have_dp) {
|
||||
verbose(VERB_QUERY, "cache has stub "
|
||||
"or fwd but no addresses, "
|
||||
"fallback to config");
|
||||
iq->dp = delegpt_copy(retdp,
|
||||
qstate->region);
|
||||
if(!iq->dp) {
|
||||
if(have_dp && !iq->dp) {
|
||||
log_err("out of memory in "
|
||||
"stub/fwd fallback");
|
||||
errinf(qstate, "malloc failure, for fallback to config");
|
||||
@@ -1644,10 +1724,11 @@ processInitRequest(struct module_qstate* qstate, struct iter_qstate* iq,
|
||||
}
|
||||
if(dname_is_root(iq->dp->name)) {
|
||||
/* use safety belt */
|
||||
int nolock = 0;
|
||||
verbose(VERB_QUERY, "Cache has root NS but "
|
||||
"no addresses. Fallback to the safety belt.");
|
||||
iq->dp = hints_lookup_root(qstate->env->hints,
|
||||
iq->qchase.qclass);
|
||||
iq->dp = hints_find_root(qstate->env->hints,
|
||||
iq->qchase.qclass, nolock);
|
||||
/* note deleg_msg is from previous lookup,
|
||||
* but RD is on, so it is not used */
|
||||
if(!iq->dp) {
|
||||
@@ -1656,6 +1737,7 @@ processInitRequest(struct module_qstate* qstate, struct iter_qstate* iq,
|
||||
LDNS_RCODE_REFUSED);
|
||||
}
|
||||
iq->dp = delegpt_copy(iq->dp, qstate->region);
|
||||
lock_rw_unlock(&qstate->env->hints->lock);
|
||||
if(!iq->dp) {
|
||||
log_err("out of memory in safety belt");
|
||||
errinf(qstate, "malloc failure, in safety belt, for root");
|
||||
@@ -1711,6 +1793,7 @@ processInitRequest2(struct module_qstate* qstate, struct iter_qstate* iq,
|
||||
delnamelen = iq->qchase.qname_len;
|
||||
if(iq->refetch_glue) {
|
||||
struct iter_hints_stub* stub;
|
||||
int nolock = 0;
|
||||
if(!iq->dp) {
|
||||
log_err("internal or malloc fail: no dp for refetch");
|
||||
errinf(qstate, "malloc failure, no delegation info");
|
||||
@@ -1720,12 +1803,14 @@ processInitRequest2(struct module_qstate* qstate, struct iter_qstate* iq,
|
||||
* this is above stub without stub-first. */
|
||||
stub = hints_lookup_stub(
|
||||
qstate->env->hints, iq->qchase.qname, iq->qchase.qclass,
|
||||
iq->dp);
|
||||
iq->dp, nolock);
|
||||
if(!stub || !stub->dp->has_parent_side_NS ||
|
||||
dname_subdomain_c(iq->dp->name, stub->dp->name)) {
|
||||
delname = iq->dp->name;
|
||||
delnamelen = iq->dp->namelen;
|
||||
}
|
||||
/* lock_() calls are macros that could be nothing, surround in {} */
|
||||
if(stub) { lock_rw_unlock(&qstate->env->hints->lock); }
|
||||
}
|
||||
if(iq->qchase.qtype == LDNS_RR_TYPE_DS || iq->refetch_glue) {
|
||||
if(!dname_is_root(delname))
|
||||
@@ -1889,7 +1974,8 @@ generate_target_query(struct module_qstate* qstate, struct iter_qstate* iq,
|
||||
* if it is negative, there is no maximum number of targets.
|
||||
* @param num: returns the number of queries generated and processed,
|
||||
* which may be zero if there were no missing targets.
|
||||
* @return false on error.
|
||||
* @return 0 on success, nonzero on error. 1 means temporary failure and
|
||||
* 2 means the failure can be cached.
|
||||
*/
|
||||
static int
|
||||
query_for_targets(struct module_qstate* qstate, struct iter_qstate* iq,
|
||||
@@ -1912,13 +1998,13 @@ query_for_targets(struct module_qstate* qstate, struct iter_qstate* iq,
|
||||
else toget = maxtargets;
|
||||
if(toget == 0) {
|
||||
*num = 0;
|
||||
return 1;
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* now that we are sure that a target query is going to be made,
|
||||
* check the limits. */
|
||||
if(iq->depth == ie->max_dependency_depth)
|
||||
return 0;
|
||||
return 1;
|
||||
if(iq->depth > 0 && iq->target_count &&
|
||||
iq->target_count[TARGET_COUNT_QUERIES] > MAX_TARGET_COUNT) {
|
||||
char s[LDNS_MAX_DOMAINLEN+1];
|
||||
@@ -1926,7 +2012,7 @@ query_for_targets(struct module_qstate* qstate, struct iter_qstate* iq,
|
||||
verbose(VERB_QUERY, "request %s has exceeded the maximum "
|
||||
"number of glue fetches %d", s,
|
||||
iq->target_count[TARGET_COUNT_QUERIES]);
|
||||
return 0;
|
||||
return 2;
|
||||
}
|
||||
if(iq->dp_target_count > MAX_DP_TARGET_COUNT) {
|
||||
char s[LDNS_MAX_DOMAINLEN+1];
|
||||
@@ -1934,7 +2020,7 @@ query_for_targets(struct module_qstate* qstate, struct iter_qstate* iq,
|
||||
verbose(VERB_QUERY, "request %s has exceeded the maximum "
|
||||
"number of glue fetches %d to a single delegation point",
|
||||
s, iq->dp_target_count);
|
||||
return 0;
|
||||
return 2;
|
||||
}
|
||||
|
||||
/* select 'toget' items from the total of 'missing' items */
|
||||
@@ -1963,7 +2049,7 @@ query_for_targets(struct module_qstate* qstate, struct iter_qstate* iq,
|
||||
*num = query_count;
|
||||
if(query_count > 0)
|
||||
qstate->ext_state[id] = module_wait_subquery;
|
||||
return 0;
|
||||
return 1;
|
||||
}
|
||||
query_count++;
|
||||
/* If the mesh query list is full, exit the loop here.
|
||||
@@ -1972,8 +2058,16 @@ query_for_targets(struct module_qstate* qstate, struct iter_qstate* iq,
|
||||
* increase, because the spawned state uses cpu and a
|
||||
* socket while this state waits for that spawned
|
||||
* state. Next time we can look up further targets */
|
||||
if(mesh_jostle_exceeded(qstate->env->mesh))
|
||||
if(mesh_jostle_exceeded(qstate->env->mesh)) {
|
||||
/* If no ip4 query is possible, that makes
|
||||
* this ns resolved. */
|
||||
if(!((ie->supports_ipv4 || ie->use_nat64) &&
|
||||
((ns->lame && !ns->done_pside4) ||
|
||||
(!ns->lame && !ns->got4)))) {
|
||||
ns->resolved = 1;
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
/* Send the A request. */
|
||||
if((ie->supports_ipv4 || ie->use_nat64) &&
|
||||
@@ -1985,12 +2079,17 @@ query_for_targets(struct module_qstate* qstate, struct iter_qstate* iq,
|
||||
*num = query_count;
|
||||
if(query_count > 0)
|
||||
qstate->ext_state[id] = module_wait_subquery;
|
||||
return 0;
|
||||
return 1;
|
||||
}
|
||||
query_count++;
|
||||
/* If the mesh query list is full, exit the loop. */
|
||||
if(mesh_jostle_exceeded(qstate->env->mesh))
|
||||
if(mesh_jostle_exceeded(qstate->env->mesh)) {
|
||||
/* With the ip6 query already checked for,
|
||||
* this makes the ns resolved. It is no longer
|
||||
* a missing target. */
|
||||
ns->resolved = 1;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/* mark this target as in progress. */
|
||||
@@ -2004,7 +2103,7 @@ query_for_targets(struct module_qstate* qstate, struct iter_qstate* iq,
|
||||
if(query_count > 0)
|
||||
qstate->ext_state[id] = module_wait_subquery;
|
||||
|
||||
return 1;
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -2029,7 +2128,7 @@ processLastResort(struct module_qstate* qstate, struct iter_qstate* iq,
|
||||
log_assert(iq->dp);
|
||||
|
||||
if(!can_have_last_resort(qstate->env, iq->dp->name, iq->dp->namelen,
|
||||
iq->qchase.qclass, NULL)) {
|
||||
iq->qchase.qclass, NULL, NULL, NULL)) {
|
||||
/* fail -- no more targets, no more hope of targets, no hope
|
||||
* of a response. */
|
||||
errinf(qstate, "all the configured stub or forward servers failed,");
|
||||
@@ -2039,21 +2138,24 @@ processLastResort(struct module_qstate* qstate, struct iter_qstate* iq,
|
||||
return error_response_cache(qstate, id, LDNS_RCODE_SERVFAIL);
|
||||
}
|
||||
if(!iq->dp->has_parent_side_NS && dname_is_root(iq->dp->name)) {
|
||||
struct delegpt* p = hints_lookup_root(qstate->env->hints,
|
||||
iq->qchase.qclass);
|
||||
if(p) {
|
||||
struct delegpt* dp;
|
||||
int nolock = 0;
|
||||
dp = hints_find_root(qstate->env->hints,
|
||||
iq->qchase.qclass, nolock);
|
||||
if(dp) {
|
||||
struct delegpt_addr* a;
|
||||
iq->chase_flags &= ~BIT_RD; /* go to authorities */
|
||||
for(ns = p->nslist; ns; ns=ns->next) {
|
||||
for(ns = dp->nslist; ns; ns=ns->next) {
|
||||
(void)delegpt_add_ns(iq->dp, qstate->region,
|
||||
ns->name, ns->lame, ns->tls_auth_name,
|
||||
ns->port);
|
||||
}
|
||||
for(a = p->target_list; a; a=a->next_target) {
|
||||
for(a = dp->target_list; a; a=a->next_target) {
|
||||
(void)delegpt_add_addr(iq->dp, qstate->region,
|
||||
&a->addr, a->addrlen, a->bogus,
|
||||
a->lame, a->tls_auth_name, -1, NULL);
|
||||
}
|
||||
lock_rw_unlock(&qstate->env->hints->lock);
|
||||
}
|
||||
iq->dp->has_parent_side_NS = 1;
|
||||
} else if(!iq->dp->has_parent_side_NS) {
|
||||
@@ -2092,12 +2194,14 @@ processLastResort(struct module_qstate* qstate, struct iter_qstate* iq,
|
||||
}
|
||||
/* query for an extra name added by the parent-NS record */
|
||||
if(delegpt_count_missing_targets(iq->dp, NULL) > 0) {
|
||||
int qs = 0;
|
||||
int qs = 0, ret;
|
||||
verbose(VERB_ALGO, "try parent-side target name");
|
||||
if(!query_for_targets(qstate, iq, ie, id, 1, &qs)) {
|
||||
if((ret=query_for_targets(qstate, iq, ie, id, 1, &qs))!=0) {
|
||||
errinf(qstate, "could not fetch nameserver");
|
||||
errinf_dname(qstate, "at zone", iq->dp->name);
|
||||
return error_response(qstate, id, LDNS_RCODE_SERVFAIL);
|
||||
if(ret == 1)
|
||||
return error_response(qstate, id, LDNS_RCODE_SERVFAIL);
|
||||
return error_response_cache(qstate, id, LDNS_RCODE_SERVFAIL);
|
||||
}
|
||||
iq->num_target_queries += qs;
|
||||
target_count_increase(iq, qs);
|
||||
@@ -2131,7 +2235,7 @@ processLastResort(struct module_qstate* qstate, struct iter_qstate* iq,
|
||||
if( ((ie->supports_ipv6 && !ns->done_pside6) ||
|
||||
((ie->supports_ipv4 || ie->use_nat64) && !ns->done_pside4)) &&
|
||||
!can_have_last_resort(qstate->env, ns->name, ns->namelen,
|
||||
iq->qchase.qclass, NULL)) {
|
||||
iq->qchase.qclass, NULL, NULL, NULL)) {
|
||||
log_nametypeclass(VERB_ALGO, "cannot pside lookup ns "
|
||||
"because it is also a stub/forward,",
|
||||
ns->name, LDNS_RR_TYPE_NS, iq->qchase.qclass);
|
||||
@@ -2326,13 +2430,13 @@ processQueryTargets(struct module_qstate* qstate, struct iter_qstate* iq,
|
||||
verbose(VERB_QUERY, "request has exceeded the maximum "
|
||||
"number of referrrals with %d", iq->referral_count);
|
||||
errinf(qstate, "exceeded the maximum of referrals");
|
||||
return error_response(qstate, id, LDNS_RCODE_SERVFAIL);
|
||||
return error_response_cache(qstate, id, LDNS_RCODE_SERVFAIL);
|
||||
}
|
||||
if(iq->sent_count > ie->max_sent_count) {
|
||||
verbose(VERB_QUERY, "request has exceeded the maximum "
|
||||
"number of sends with %d", iq->sent_count);
|
||||
errinf(qstate, "exceeded the maximum number of sends");
|
||||
return error_response(qstate, id, LDNS_RCODE_SERVFAIL);
|
||||
return error_response_cache(qstate, id, LDNS_RCODE_SERVFAIL);
|
||||
}
|
||||
|
||||
/* Check if we reached MAX_TARGET_NX limit without a fallback activation. */
|
||||
@@ -2362,7 +2466,7 @@ processQueryTargets(struct module_qstate* qstate, struct iter_qstate* iq,
|
||||
"already present for the delegation point, no "
|
||||
"fallback possible");
|
||||
errinf(qstate, "exceeded the maximum nameserver nxdomains");
|
||||
return error_response(qstate, id, LDNS_RCODE_SERVFAIL);
|
||||
return error_response_cache(qstate, id, LDNS_RCODE_SERVFAIL);
|
||||
}
|
||||
verbose(VERB_ALGO, "initiating parent-side fallback for "
|
||||
"nxdomain nameserver lookups");
|
||||
@@ -2405,7 +2509,7 @@ processQueryTargets(struct module_qstate* qstate, struct iter_qstate* iq,
|
||||
"lookups (%d) with %d", MAX_TARGET_NX_FALLBACK,
|
||||
iq->target_count[TARGET_COUNT_NX]);
|
||||
errinf(qstate, "exceeded the maximum nameserver nxdomains");
|
||||
return error_response(qstate, id, LDNS_RCODE_SERVFAIL);
|
||||
return error_response_cache(qstate, id, LDNS_RCODE_SERVFAIL);
|
||||
}
|
||||
|
||||
if(!iq->dp->has_parent_side_NS) {
|
||||
@@ -2619,7 +2723,7 @@ processQueryTargets(struct module_qstate* qstate, struct iter_qstate* iq,
|
||||
verbose(VERB_ALGO, "auth zone lookup failed, no fallback,"
|
||||
" servfail");
|
||||
errinf(qstate, "auth zone lookup failed, fallback is off");
|
||||
return error_response(qstate, id, LDNS_RCODE_SERVFAIL);
|
||||
return error_response_cache(qstate, id, LDNS_RCODE_SERVFAIL);
|
||||
}
|
||||
if(iq->dp->auth_dp) {
|
||||
/* we wanted to fallback, but had no delegpt, only the
|
||||
@@ -2648,11 +2752,13 @@ processQueryTargets(struct module_qstate* qstate, struct iter_qstate* iq,
|
||||
|
||||
/* if in 0x20 fallback get as many targets as possible */
|
||||
if(iq->caps_fallback) {
|
||||
int extra = 0;
|
||||
int extra = 0, ret;
|
||||
size_t naddr, nres, navail;
|
||||
if(!query_for_targets(qstate, iq, ie, id, -1, &extra)) {
|
||||
if((ret=query_for_targets(qstate, iq, ie, id, -1, &extra))!=0) {
|
||||
errinf(qstate, "could not fetch nameservers for 0x20 fallback");
|
||||
return error_response(qstate, id, LDNS_RCODE_SERVFAIL);
|
||||
if(ret == 1)
|
||||
return error_response(qstate, id, LDNS_RCODE_SERVFAIL);
|
||||
return error_response_cache(qstate, id, LDNS_RCODE_SERVFAIL);
|
||||
}
|
||||
iq->num_target_queries += extra;
|
||||
target_count_increase(iq, extra);
|
||||
@@ -2713,8 +2819,51 @@ processQueryTargets(struct module_qstate* qstate, struct iter_qstate* iq,
|
||||
delegpt_add_unused_targets(iq->dp);
|
||||
|
||||
if(qstate->env->auth_zones) {
|
||||
/* apply rpz triggers at query time */
|
||||
uint8_t* sname = NULL;
|
||||
size_t snamelen = 0;
|
||||
/* apply rpz triggers at query time; nameserver IP and dname */
|
||||
struct dns_msg* forged_response_after_cname;
|
||||
struct dns_msg* forged_response = rpz_callback_from_iterator_module(qstate, iq);
|
||||
int count = 0;
|
||||
while(forged_response && reply_find_rrset_section_an(
|
||||
forged_response->rep, iq->qchase.qname,
|
||||
iq->qchase.qname_len, LDNS_RR_TYPE_CNAME,
|
||||
iq->qchase.qclass) &&
|
||||
iq->qchase.qtype != LDNS_RR_TYPE_CNAME &&
|
||||
count++ < ie->max_query_restarts) {
|
||||
/* another cname to follow */
|
||||
if(!handle_cname_response(qstate, iq, forged_response,
|
||||
&sname, &snamelen)) {
|
||||
errinf(qstate, "malloc failure, CNAME info");
|
||||
return error_response(qstate, id, LDNS_RCODE_SERVFAIL);
|
||||
}
|
||||
iq->qchase.qname = sname;
|
||||
iq->qchase.qname_len = snamelen;
|
||||
forged_response_after_cname =
|
||||
rpz_callback_from_iterator_cname(qstate, iq);
|
||||
if(forged_response_after_cname) {
|
||||
forged_response = forged_response_after_cname;
|
||||
} else {
|
||||
/* Follow the CNAME with a query restart */
|
||||
iq->deleg_msg = NULL;
|
||||
iq->dp = NULL;
|
||||
iq->dsns_point = NULL;
|
||||
iq->auth_zone_response = 0;
|
||||
iq->refetch_glue = 0;
|
||||
iq->query_restart_count++;
|
||||
iq->sent_count = 0;
|
||||
iq->dp_target_count = 0;
|
||||
if(qstate->env->cfg->qname_minimisation)
|
||||
iq->minimisation_state = INIT_MINIMISE_STATE;
|
||||
outbound_list_clear(&iq->outlist);
|
||||
iq->num_current_queries = 0;
|
||||
fptr_ok(fptr_whitelist_modenv_detach_subs(
|
||||
qstate->env->detach_subs));
|
||||
(*qstate->env->detach_subs)(qstate);
|
||||
iq->num_target_queries = 0;
|
||||
return next_state(iq, INIT_REQUEST_STATE);
|
||||
}
|
||||
}
|
||||
if(forged_response != NULL) {
|
||||
qstate->ext_state[id] = module_finished;
|
||||
qstate->return_rcode = LDNS_RCODE_NOERROR;
|
||||
@@ -2752,14 +2901,17 @@ processQueryTargets(struct module_qstate* qstate, struct iter_qstate* iq,
|
||||
* to distinguish between generating (a) new target
|
||||
* query, or failing. */
|
||||
if(delegpt_count_missing_targets(iq->dp, NULL) > 0) {
|
||||
int qs = 0;
|
||||
int qs = 0, ret;
|
||||
verbose(VERB_ALGO, "querying for next "
|
||||
"missing target");
|
||||
if(!query_for_targets(qstate, iq, ie, id,
|
||||
1, &qs)) {
|
||||
if((ret=query_for_targets(qstate, iq, ie, id,
|
||||
1, &qs))!=0) {
|
||||
errinf(qstate, "could not fetch nameserver");
|
||||
errinf_dname(qstate, "at zone", iq->dp->name);
|
||||
return error_response(qstate, id,
|
||||
if(ret == 1)
|
||||
return error_response(qstate, id,
|
||||
LDNS_RCODE_SERVFAIL);
|
||||
return error_response_cache(qstate, id,
|
||||
LDNS_RCODE_SERVFAIL);
|
||||
}
|
||||
if(qs == 0 &&
|
||||
@@ -2771,6 +2923,17 @@ processQueryTargets(struct module_qstate* qstate, struct iter_qstate* iq,
|
||||
* so this is not a loop. */
|
||||
return 1;
|
||||
}
|
||||
if(qs == 0) {
|
||||
/* There should be targets now, and
|
||||
* if there are not, it should not
|
||||
* wait for no targets. Stop it from
|
||||
* waiting forever, or looping to
|
||||
* here, as a safeguard. */
|
||||
errinf(qstate, "could not generate nameserver lookups");
|
||||
errinf_dname(qstate, "at zone", iq->dp->name);
|
||||
return error_response(qstate, id,
|
||||
LDNS_RCODE_SERVFAIL);
|
||||
}
|
||||
iq->num_target_queries += qs;
|
||||
target_count_increase(iq, qs);
|
||||
}
|
||||
@@ -2875,7 +3038,8 @@ processQueryTargets(struct module_qstate* qstate, struct iter_qstate* iq,
|
||||
/* unset CD if to forwarder(RD set) and not dnssec retry
|
||||
* (blacklist nonempty) and no trust-anchors are configured
|
||||
* above the qname or on the first attempt when dnssec is on */
|
||||
EDNS_DO| ((iq->chase_to_rd||(iq->chase_flags&BIT_RD)!=0)&&
|
||||
(qstate->env->cfg->disable_edns_do?0:EDNS_DO)|
|
||||
((iq->chase_to_rd||(iq->chase_flags&BIT_RD)!=0)&&
|
||||
!qstate->blacklist&&(!iter_qname_indicates_dnssec(qstate->env,
|
||||
&iq->qinfo_out)||target->attempts==1)?0:BIT_CD),
|
||||
iq->dnssec_expected, iq->caps_fallback || is_caps_whitelisted(
|
||||
@@ -2893,7 +3057,7 @@ processQueryTargets(struct module_qstate* qstate, struct iter_qstate* iq,
|
||||
qstate->was_ratelimited = 1;
|
||||
errinf_dname(qstate, "exceeded ratelimit for zone",
|
||||
iq->dp->name);
|
||||
return error_response(qstate, id, LDNS_RCODE_SERVFAIL);
|
||||
return error_response_cache(qstate, id, LDNS_RCODE_SERVFAIL);
|
||||
}
|
||||
log_addr(VERB_QUERY, "error sending query to auth server",
|
||||
&real_addr, real_addrlen);
|
||||
@@ -2940,7 +3104,7 @@ static int
|
||||
processQueryResponse(struct module_qstate* qstate, struct iter_qstate* iq,
|
||||
struct iter_env* ie, int id)
|
||||
{
|
||||
int dnsseclame = 0, origtypecname = 0;
|
||||
int dnsseclame = 0, origtypecname = 0, orig_empty_nodata_found;
|
||||
enum response_type type;
|
||||
|
||||
iq->num_current_queries--;
|
||||
@@ -2960,12 +3124,25 @@ processQueryResponse(struct module_qstate* qstate, struct iter_qstate* iq,
|
||||
return next_state(iq, QUERYTARGETS_STATE);
|
||||
}
|
||||
iq->timeout_count = 0;
|
||||
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->response, &iq->qinfo_out, iq->dp, &iq->empty_nodata_found);
|
||||
iq->chase_to_rd = 0;
|
||||
/* remove TC flag, if this is erroneously set by TCP upstream */
|
||||
iq->response->rep->flags &= ~BIT_TC;
|
||||
if(orig_empty_nodata_found != iq->empty_nodata_found &&
|
||||
iq->empty_nodata_found < EMPTY_NODATA_RETRY_COUNT) {
|
||||
/* try to search at another server */
|
||||
if(qstate->reply) {
|
||||
struct delegpt_addr* a = delegpt_find_addr(
|
||||
iq->dp, &qstate->reply->remote_addr,
|
||||
qstate->reply->remote_addrlen);
|
||||
/* make selection disprefer it */
|
||||
if(a) a->lame = 1;
|
||||
}
|
||||
return next_state(iq, QUERYTARGETS_STATE);
|
||||
}
|
||||
if(type == RESPONSE_TYPE_REFERRAL && (iq->chase_flags&BIT_RD) &&
|
||||
!iq->auth_zone_response) {
|
||||
/* When forwarding (RD bit is set), we handle referrals
|
||||
@@ -3035,7 +3212,8 @@ processQueryResponse(struct module_qstate* qstate, struct iter_qstate* iq,
|
||||
/* DNAME to a subdomain loop; do not recurse */
|
||||
type = RESPONSE_TYPE_ANSWER;
|
||||
}
|
||||
} else if(type == RESPONSE_TYPE_CNAME &&
|
||||
}
|
||||
if(type == RESPONSE_TYPE_CNAME &&
|
||||
iq->qchase.qtype == LDNS_RR_TYPE_CNAME &&
|
||||
iq->minimisation_state == MINIMISE_STATE &&
|
||||
query_dname_compare(iq->qchase.qname, iq->qinfo_out.qname) == 0) {
|
||||
@@ -3101,7 +3279,7 @@ processQueryResponse(struct module_qstate* qstate, struct iter_qstate* iq,
|
||||
iter_scrub_nxdomain(iq->response);
|
||||
return final_state(iq);
|
||||
}
|
||||
return error_response(qstate, id,
|
||||
return error_response_cache(qstate, id,
|
||||
LDNS_RCODE_SERVFAIL);
|
||||
}
|
||||
/* Best effort qname-minimisation.
|
||||
@@ -3146,6 +3324,7 @@ processQueryResponse(struct module_qstate* qstate, struct iter_qstate* iq,
|
||||
}
|
||||
return final_state(iq);
|
||||
} else if(type == RESPONSE_TYPE_REFERRAL) {
|
||||
struct delegpt* old_dp = NULL;
|
||||
/* REFERRAL type responses get a reset of the
|
||||
* delegation point, and back to the QUERYTARGETS_STATE. */
|
||||
verbose(VERB_DETAIL, "query response was REFERRAL");
|
||||
@@ -3197,6 +3376,8 @@ processQueryResponse(struct module_qstate* qstate, struct iter_qstate* iq,
|
||||
/* Reset the event state, setting the current delegation
|
||||
* point to the referral. */
|
||||
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);
|
||||
if (qstate->env->cfg->qname_minimisation)
|
||||
iq->minimisation_state = INIT_MINIMISE_STATE;
|
||||
@@ -3204,6 +3385,20 @@ processQueryResponse(struct module_qstate* qstate, struct iter_qstate* iq,
|
||||
errinf(qstate, "malloc failure, for delegation point");
|
||||
return error_response(qstate, id, LDNS_RCODE_SERVFAIL);
|
||||
}
|
||||
if(old_dp->namelabs + 1 < iq->dp->namelabs) {
|
||||
/* We got a grandchild delegation (more than one label
|
||||
* difference) than expected. Check for in-between
|
||||
* delegations in the cache and remove them.
|
||||
* They could prove problematic when they expire
|
||||
* and rrset_expired_above() encounters them during
|
||||
* delegation cache lookups. */
|
||||
uint8_t* qname = iq->dp->name;
|
||||
size_t qnamelen = iq->dp->namelen;
|
||||
rrset_cache_remove_above(qstate->env->rrset_cache,
|
||||
&qname, &qnamelen, LDNS_RR_TYPE_NS,
|
||||
iq->qchase.qclass, *qstate->env->now,
|
||||
old_dp->name, old_dp->namelen);
|
||||
}
|
||||
if(!cache_fill_missing(qstate->env, iq->qchase.qclass,
|
||||
qstate->region, iq->dp)) {
|
||||
errinf(qstate, "malloc failure, copy extra info into delegation point");
|
||||
@@ -3294,10 +3489,13 @@ processQueryResponse(struct module_qstate* qstate, struct iter_qstate* iq,
|
||||
/* apply rpz qname triggers after cname */
|
||||
struct dns_msg* forged_response =
|
||||
rpz_callback_from_iterator_cname(qstate, iq);
|
||||
int count = 0;
|
||||
while(forged_response && reply_find_rrset_section_an(
|
||||
forged_response->rep, iq->qchase.qname,
|
||||
iq->qchase.qname_len, LDNS_RR_TYPE_CNAME,
|
||||
iq->qchase.qclass)) {
|
||||
iq->qchase.qclass) &&
|
||||
iq->qchase.qtype != LDNS_RR_TYPE_CNAME &&
|
||||
count++ < ie->max_query_restarts) {
|
||||
/* another cname to follow */
|
||||
if(!handle_cname_response(qstate, iq, forged_response,
|
||||
&sname, &snamelen)) {
|
||||
@@ -3416,7 +3614,7 @@ processQueryResponse(struct module_qstate* qstate, struct iter_qstate* iq,
|
||||
" fallback possible, servfail");
|
||||
errinf_dname(qstate, "response is bad, no fallback, "
|
||||
"for auth zone", iq->dp->name);
|
||||
return error_response(qstate, id, LDNS_RCODE_SERVFAIL);
|
||||
return error_response_cache(qstate, id, LDNS_RCODE_SERVFAIL);
|
||||
}
|
||||
verbose(VERB_ALGO, "auth zone response was bad, "
|
||||
"fallback enabled");
|
||||
@@ -3501,7 +3699,7 @@ 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);
|
||||
iq->response, &iq->qchase, iq->dp, NULL);
|
||||
if(type == RESPONSE_TYPE_ANSWER) {
|
||||
qstate->return_rcode = LDNS_RCODE_NOERROR;
|
||||
qstate->return_msg = iq->response;
|
||||
@@ -3824,7 +4022,7 @@ processCollectClass(struct module_qstate* qstate, int id)
|
||||
if(iq->num_current_queries == 0) {
|
||||
verbose(VERB_ALGO, "No root hints or fwds, giving up "
|
||||
"on qclass ANY");
|
||||
return error_response(qstate, id, LDNS_RCODE_REFUSED);
|
||||
return error_response_cache(qstate, id, LDNS_RCODE_REFUSED);
|
||||
}
|
||||
/* return false, wait for queries to return */
|
||||
}
|
||||
@@ -3874,6 +4072,15 @@ processFinished(struct module_qstate* qstate, struct iter_qstate* iq,
|
||||
|
||||
/* explicitly set the EDE string to NULL */
|
||||
iq->response->rep->reason_bogus_str = NULL;
|
||||
if((qstate->env->cfg->val_log_level >= 2 ||
|
||||
qstate->env->cfg->log_servfail) && qstate->errinf &&
|
||||
!qstate->env->cfg->val_log_squelch) {
|
||||
char* err_str = errinf_to_str_misc(qstate);
|
||||
if(err_str) {
|
||||
verbose(VERB_ALGO, "iterator EDE: %s", err_str);
|
||||
iq->response->rep->reason_bogus_str = err_str;
|
||||
}
|
||||
}
|
||||
|
||||
/* we have finished processing this query */
|
||||
qstate->ext_state[id] = module_finished;
|
||||
@@ -4087,10 +4294,10 @@ process_response(struct module_qstate* qstate, struct iter_qstate* iq,
|
||||
/* like packet got dropped */
|
||||
goto handle_it;
|
||||
}
|
||||
if(!inplace_cb_edns_back_parsed_call(qstate->env, qstate)) {
|
||||
log_err("unable to call edns_back_parsed callback");
|
||||
goto handle_it;
|
||||
}
|
||||
}
|
||||
if(!inplace_cb_edns_back_parsed_call(qstate->env, qstate)) {
|
||||
log_err("unable to call edns_back_parsed callback");
|
||||
goto handle_it;
|
||||
}
|
||||
|
||||
/* remove CD-bit, we asked for in case we handle validation ourself */
|
||||
@@ -4098,7 +4305,7 @@ 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, ie)) {
|
||||
qstate->env->scratch, qstate->env, qstate, ie)) {
|
||||
/* if 0x20 enabled, start fallback, but we have no message */
|
||||
if(event == module_event_capsfail && !iq->caps_fallback) {
|
||||
iq->caps_fallback = 1;
|
||||
@@ -4182,7 +4389,7 @@ process_response(struct module_qstate* qstate, struct iter_qstate* iq,
|
||||
"getting different replies, failed");
|
||||
outbound_list_remove(&iq->outlist, outbound);
|
||||
errinf(qstate, "0x20 failed, then got different replies in fallback");
|
||||
(void)error_response(qstate, id,
|
||||
(void)error_response_cache(qstate, id,
|
||||
LDNS_RCODE_SERVFAIL);
|
||||
return;
|
||||
}
|
||||
@@ -4282,8 +4489,8 @@ iter_get_mem(struct module_env* env, int id)
|
||||
*/
|
||||
static struct module_func_block iter_block = {
|
||||
"iterator",
|
||||
&iter_init, &iter_deinit, &iter_operate, &iter_inform_super,
|
||||
&iter_clear, &iter_get_mem
|
||||
NULL, NULL, &iter_init, &iter_deinit, &iter_operate,
|
||||
&iter_inform_super, &iter_clear, &iter_get_mem
|
||||
};
|
||||
|
||||
struct module_func_block*
|
||||
|
||||
@@ -101,6 +101,8 @@ extern int BLACKLIST_PENALTY;
|
||||
* Chosen so that the UNKNOWN_SERVER_NICENESS falls within the band of a
|
||||
* fast server, this causes server exploration as a side benefit. msec. */
|
||||
#define RTT_BAND 400
|
||||
/** Number of retries for empty nodata packets before it is accepted. */
|
||||
#define EMPTY_NODATA_RETRY_COUNT 2
|
||||
|
||||
/**
|
||||
* Global state for the iterator.
|
||||
@@ -415,6 +417,11 @@ struct iter_qstate {
|
||||
*/
|
||||
int refetch_glue;
|
||||
|
||||
/**
|
||||
* This flag detects that a completely empty nodata was received,
|
||||
* already so that it is accepted later. */
|
||||
int empty_nodata_found;
|
||||
|
||||
/** list of pending queries to authoritative servers. */
|
||||
struct outbound_list outlist;
|
||||
|
||||
|
||||
+11
-1
@@ -53,6 +53,8 @@
|
||||
#include "util/storage/slabhash.h"
|
||||
#include "util/edns.h"
|
||||
#include "sldns/sbuffer.h"
|
||||
#include "iterator/iter_fwd.h"
|
||||
#include "iterator/iter_hints.h"
|
||||
|
||||
int
|
||||
context_finalize(struct ub_ctx* ctx)
|
||||
@@ -73,7 +75,9 @@ context_finalize(struct ub_ctx* ctx)
|
||||
ctx->pipe_pid = getpid();
|
||||
cfg_apply_local_port_policy(cfg, 65536);
|
||||
config_apply(cfg);
|
||||
if(!modstack_setup(&ctx->mods, cfg->module_conf, ctx->env))
|
||||
if(!modstack_call_startup(&ctx->mods, cfg->module_conf, ctx->env))
|
||||
return UB_INITFAIL;
|
||||
if(!modstack_call_init(&ctx->mods, cfg->module_conf, ctx->env))
|
||||
return UB_INITFAIL;
|
||||
listen_setup_locks();
|
||||
log_edns_known_options(VERB_ALGO, ctx->env);
|
||||
@@ -85,6 +89,12 @@ context_finalize(struct ub_ctx* ctx)
|
||||
if(!auth_zones_apply_cfg(ctx->env->auth_zones, cfg, 1, &is_rpz,
|
||||
ctx->env, &ctx->mods))
|
||||
return UB_INITFAIL;
|
||||
if(!(ctx->env->fwds = forwards_create()) ||
|
||||
!forwards_apply_cfg(ctx->env->fwds, cfg))
|
||||
return UB_INITFAIL;
|
||||
if(!(ctx->env->hints = hints_create()) ||
|
||||
!hints_apply_cfg(ctx->env->hints, cfg))
|
||||
return UB_INITFAIL;
|
||||
if(!edns_strings_apply_cfg(ctx->env->edns_strings, cfg))
|
||||
return UB_INITFAIL;
|
||||
if(!slabhash_is_size(ctx->env->msg_cache, cfg->msg_cache_size,
|
||||
|
||||
+19
-5
@@ -66,6 +66,8 @@
|
||||
#include "services/authzone.h"
|
||||
#include "services/listen_dnsport.h"
|
||||
#include "sldns/sbuffer.h"
|
||||
#include "iterator/iter_fwd.h"
|
||||
#include "iterator/iter_hints.h"
|
||||
#ifdef HAVE_PTHREAD
|
||||
#include <signal.h>
|
||||
#endif
|
||||
@@ -171,6 +173,7 @@ static struct ub_ctx* ub_ctx_create_nopipe(void)
|
||||
ctx->env->worker = NULL;
|
||||
ctx->env->need_to_validate = 0;
|
||||
modstack_init(&ctx->mods);
|
||||
ctx->env->modstack = &ctx->mods;
|
||||
rbtree_init(&ctx->queries, &context_query_cmp);
|
||||
return ctx;
|
||||
}
|
||||
@@ -185,7 +188,9 @@ ub_ctx_create(void)
|
||||
int e = errno;
|
||||
ub_randfree(ctx->seed_rnd);
|
||||
config_delete(ctx->env->cfg);
|
||||
modstack_desetup(&ctx->mods, ctx->env);
|
||||
modstack_call_deinit(&ctx->mods, ctx->env);
|
||||
modstack_call_destartup(&ctx->mods, ctx->env);
|
||||
modstack_free(&ctx->mods);
|
||||
listen_desetup_locks();
|
||||
edns_known_options_delete(ctx->env);
|
||||
edns_strings_delete(ctx->env->edns_strings);
|
||||
@@ -199,7 +204,9 @@ ub_ctx_create(void)
|
||||
tube_delete(ctx->qq_pipe);
|
||||
ub_randfree(ctx->seed_rnd);
|
||||
config_delete(ctx->env->cfg);
|
||||
modstack_desetup(&ctx->mods, ctx->env);
|
||||
modstack_call_deinit(&ctx->mods, ctx->env);
|
||||
modstack_call_destartup(&ctx->mods, ctx->env);
|
||||
modstack_free(&ctx->mods);
|
||||
listen_desetup_locks();
|
||||
edns_known_options_delete(ctx->env);
|
||||
edns_strings_delete(ctx->env->edns_strings);
|
||||
@@ -357,7 +364,9 @@ ub_ctx_delete(struct ub_ctx* ctx)
|
||||
}
|
||||
libworker_delete_event(ctx->event_worker);
|
||||
|
||||
modstack_desetup(&ctx->mods, ctx->env);
|
||||
modstack_call_deinit(&ctx->mods, ctx->env);
|
||||
modstack_call_destartup(&ctx->mods, ctx->env);
|
||||
modstack_free(&ctx->mods);
|
||||
a = ctx->alloc_list;
|
||||
while(a) {
|
||||
na = a->super;
|
||||
@@ -379,6 +388,8 @@ ub_ctx_delete(struct ub_ctx* ctx)
|
||||
config_delete(ctx->env->cfg);
|
||||
edns_known_options_delete(ctx->env);
|
||||
edns_strings_delete(ctx->env->edns_strings);
|
||||
forwards_delete(ctx->env->fwds);
|
||||
hints_delete(ctx->env->hints);
|
||||
auth_zones_delete(ctx->env->auth_zones);
|
||||
free(ctx->env);
|
||||
}
|
||||
@@ -976,7 +987,8 @@ ub_ctx_set_fwd(struct ub_ctx* ctx, const char* addr)
|
||||
if(!addr) {
|
||||
/* disable fwd mode - the root stub should be first. */
|
||||
if(ctx->env->cfg->forwards &&
|
||||
strcmp(ctx->env->cfg->forwards->name, ".") == 0) {
|
||||
(ctx->env->cfg->forwards->name &&
|
||||
strcmp(ctx->env->cfg->forwards->name, ".") == 0)) {
|
||||
s = ctx->env->cfg->forwards;
|
||||
ctx->env->cfg->forwards = s->next;
|
||||
s->next = NULL;
|
||||
@@ -996,7 +1008,8 @@ ub_ctx_set_fwd(struct ub_ctx* ctx, const char* addr)
|
||||
/* it parses, add root stub in front of list */
|
||||
lock_basic_lock(&ctx->cfglock);
|
||||
if(!ctx->env->cfg->forwards ||
|
||||
strcmp(ctx->env->cfg->forwards->name, ".") != 0) {
|
||||
(ctx->env->cfg->forwards->name &&
|
||||
strcmp(ctx->env->cfg->forwards->name, ".") != 0)) {
|
||||
s = calloc(1, sizeof(*s));
|
||||
if(!s) {
|
||||
lock_basic_unlock(&ctx->cfglock);
|
||||
@@ -1014,6 +1027,7 @@ ub_ctx_set_fwd(struct ub_ctx* ctx, const char* addr)
|
||||
ctx->env->cfg->forwards = s;
|
||||
} else {
|
||||
log_assert(ctx->env->cfg->forwards);
|
||||
log_assert(ctx->env->cfg->forwards->name);
|
||||
s = ctx->env->cfg->forwards;
|
||||
}
|
||||
dupl = strdup(addr);
|
||||
|
||||
+7
-18
@@ -62,6 +62,7 @@
|
||||
#include "util/random.h"
|
||||
#include "util/config_file.h"
|
||||
#include "util/netevent.h"
|
||||
#include "util/proxy_protocol.h"
|
||||
#include "util/storage/lookup3.h"
|
||||
#include "util/storage/slabhash.h"
|
||||
#include "util/net_help.h"
|
||||
@@ -69,8 +70,6 @@
|
||||
#include "util/data/msgreply.h"
|
||||
#include "util/data/msgencode.h"
|
||||
#include "util/tube.h"
|
||||
#include "iterator/iter_fwd.h"
|
||||
#include "iterator/iter_hints.h"
|
||||
#include "sldns/sbuffer.h"
|
||||
#include "sldns/str2wire.h"
|
||||
#ifdef USE_DNSTAP
|
||||
@@ -99,8 +98,6 @@ libworker_delete_env(struct libworker* w)
|
||||
!w->is_bg || w->is_bg_thread);
|
||||
sldns_buffer_free(w->env->scratch_buffer);
|
||||
regional_destroy(w->env->scratch);
|
||||
forwards_delete(w->env->fwds);
|
||||
hints_delete(w->env->hints);
|
||||
ub_randfree(w->env->rnd);
|
||||
free(w->env);
|
||||
}
|
||||
@@ -158,28 +155,19 @@ libworker_setup(struct ub_ctx* ctx, int is_bg, struct ub_event_base* eb)
|
||||
}
|
||||
w->env->scratch = regional_create_custom(cfg->msg_buffer_size);
|
||||
w->env->scratch_buffer = sldns_buffer_new(cfg->msg_buffer_size);
|
||||
w->env->fwds = forwards_create();
|
||||
if(w->env->fwds && !forwards_apply_cfg(w->env->fwds, cfg)) {
|
||||
forwards_delete(w->env->fwds);
|
||||
w->env->fwds = NULL;
|
||||
}
|
||||
w->env->hints = hints_create();
|
||||
if(w->env->hints && !hints_apply_cfg(w->env->hints, cfg)) {
|
||||
hints_delete(w->env->hints);
|
||||
w->env->hints = NULL;
|
||||
}
|
||||
#ifdef HAVE_SSL
|
||||
w->sslctx = connect_sslctx_create(NULL, NULL,
|
||||
cfg->tls_cert_bundle, cfg->tls_win_cert);
|
||||
if(!w->sslctx) {
|
||||
/* to make the setup fail after unlock */
|
||||
hints_delete(w->env->hints);
|
||||
w->env->hints = NULL;
|
||||
sldns_buffer_free(w->env->scratch_buffer);
|
||||
w->env->scratch_buffer = NULL;
|
||||
}
|
||||
#endif
|
||||
if(!w->is_bg || w->is_bg_thread) {
|
||||
lock_basic_unlock(&ctx->cfglock);
|
||||
}
|
||||
if(!w->env->scratch || !w->env->scratch_buffer || !w->env->fwds ||
|
||||
!w->env->hints) {
|
||||
if(!w->env->scratch || !w->env->scratch_buffer) {
|
||||
libworker_delete(w);
|
||||
return NULL;
|
||||
}
|
||||
@@ -263,6 +251,7 @@ libworker_setup(struct ub_ctx* ctx, int is_bg, struct ub_event_base* eb)
|
||||
w->env->kill_sub = &mesh_state_delete;
|
||||
w->env->detect_cycle = &mesh_detect_cycle;
|
||||
comm_base_timept(w->base, &w->env->now, &w->env->now_tv);
|
||||
pp_init(&sldns_write_uint16, &sldns_write_uint32);
|
||||
return w;
|
||||
}
|
||||
|
||||
|
||||
@@ -863,6 +863,9 @@ Result: ['74.125.43.147', '74.125.43.99', '74.125.43.103', '74.125.43.104']
|
||||
%inline %{
|
||||
//SWIG will see the ub_ctx as a class
|
||||
struct ub_ctx {
|
||||
/* Dummy member, so the struct is not empty, MSVC complains about
|
||||
* that. */
|
||||
int dummy;
|
||||
};
|
||||
%}
|
||||
|
||||
|
||||
+147
-45
@@ -45,20 +45,24 @@ usage () {
|
||||
Usage $0: [-h] [-s] [-u git_url] [-b git_branch] [-w ...args...]
|
||||
Generate a distribution tar file for unbound.
|
||||
|
||||
-h This usage information.
|
||||
-s Build a snapshot distribution file. The current date is
|
||||
automatically appended to the current unbound version number.
|
||||
-rc <nr> Build a release candidate, the given string will be added
|
||||
to the version number
|
||||
(which will then be unbound-<version>rc<number>)
|
||||
-u git_url Retrieve the source from the specified repository url.
|
||||
Detected from the working copy if not specified.
|
||||
-b git_branch Retrieve the the specified branch or tag.
|
||||
Detected from the working copy if not specified.
|
||||
-h This usage information.
|
||||
-s Build a snapshot distribution file. The current date is
|
||||
automatically appended to the current unbound version number.
|
||||
-rc <nr> Build a release candidate, the given string will be added
|
||||
to the version number
|
||||
(which will then be unbound-<version>rc<number>)
|
||||
-u git_url Retrieve the source from the specified repository url.
|
||||
Detected from the working copy if not specified.
|
||||
-b git_branch Retrieve the specified branch or tag.
|
||||
Detected from the working copy if not specified.
|
||||
-wssl openssl.xx.tar.gz Also build openssl from tarball for windows dist.
|
||||
-wxp expat.xx.tar.gz Also build expat from tarball for windows dist.
|
||||
-w32 32bit windows compile.
|
||||
-w ... Build windows binary dist. last args passed to configure.
|
||||
-wdir directory Build openssl and expat in a persistent directory for
|
||||
windows dist. If builds are already in that directory
|
||||
they are used right away. Useful when debuggin windows
|
||||
builds.
|
||||
-w32 32bit windows compile.
|
||||
-w ... Build windows binary dist. last args passed to configure.
|
||||
EOF
|
||||
exit 1
|
||||
}
|
||||
@@ -143,6 +147,16 @@ create_temp_dir () {
|
||||
cd $temp_dir
|
||||
}
|
||||
|
||||
activate_windebug_dir () {
|
||||
info "Activating persistent directory for windows build."
|
||||
if test ! -d "$WINDIR"; then
|
||||
mkdir -p "$WINDIR"
|
||||
info "Created $WINDIR persistent directory."
|
||||
fi
|
||||
cd "$WINDIR"
|
||||
WINDIR="`pwd`"
|
||||
}
|
||||
|
||||
# pass filename as $1 arg.
|
||||
# creates file.sha1 and file.sha256
|
||||
storehash () {
|
||||
@@ -187,7 +201,9 @@ DOWIN="no"
|
||||
W64="yes"
|
||||
WINSSL=""
|
||||
WINEXPAT=""
|
||||
MINJ=""
|
||||
WINDIR=""
|
||||
# Use environment if set otherwise null
|
||||
MINJ="${MINJ:+$MINJ}"
|
||||
|
||||
# Parse the command line arguments.
|
||||
while [ "$1" ]; do
|
||||
@@ -214,6 +230,10 @@ while [ "$1" ]; do
|
||||
WINEXPAT="$2"
|
||||
shift
|
||||
;;
|
||||
"-wdir")
|
||||
WINDIR="$2"
|
||||
shift
|
||||
;;
|
||||
"-w32")
|
||||
W64="no"
|
||||
;;
|
||||
@@ -253,8 +273,27 @@ if [ "$DOWIN" = "yes" ]; then
|
||||
shared_cross_flag=""
|
||||
|
||||
check_git_repo
|
||||
create_temp_dir
|
||||
|
||||
if test -n "$WINDIR"; then
|
||||
activate_windebug_dir
|
||||
else
|
||||
create_temp_dir
|
||||
fi
|
||||
|
||||
if test -n "$WINSSL" \
|
||||
-a -n "$WINDIR" \
|
||||
-a -d "$WINDIR" \
|
||||
-a -d "${WINDIR}/sslinstall" \
|
||||
-a -d "${WINDIR}/openssl_shared" \
|
||||
-a -d "${WINDIR}/sslsharedinstall"; then
|
||||
info "Found already compiled openssl at $WINDIR/sslinstall; using that."
|
||||
WINSSL=""
|
||||
# Variables needed later on.
|
||||
sslinstall="${WINDIR}/sslinstall"
|
||||
cross_flag="$cross_flag --with-ssl=$sslinstall"
|
||||
sslsharedinstall="${WINDIR}/sslsharedinstall"
|
||||
shared_cross_flag="$shared_cross_flag --with-ssl=$sslsharedinstall"
|
||||
fi
|
||||
# crosscompile openssl for windows.
|
||||
if test -n "$WINSSL"; then
|
||||
info "Cross compile $WINSSL"
|
||||
@@ -267,10 +306,10 @@ if [ "$DOWIN" = "yes" ]; then
|
||||
# cross-compilation and it is not used anyway
|
||||
# before 1.0.1i need --cross-compile-prefix=i686-w64-mingw32-
|
||||
if test "$mw64" = "mingw64"; then
|
||||
sslflags="no-asm -DOPENSSL_NO_CAPIENG mingw64"
|
||||
sslflags="no-asm no-tests -DOPENSSL_NO_CAPIENG mingw64"
|
||||
sspdll="/usr/x86_64-w64-mingw32/sys-root/mingw/bin/libssp-0.dll"
|
||||
else
|
||||
sslflags="no-asm -DOPENSSL_NO_CAPIENG mingw"
|
||||
sslflags="no-asm no-tests -DOPENSSL_NO_CAPIENG mingw"
|
||||
sspdll="/usr/i686-w64-mingw32/sys-root/mingw/bin/libssp-0.dll"
|
||||
fi
|
||||
if test -f "$sspdll"; then
|
||||
@@ -282,9 +321,18 @@ if [ "$DOWIN" = "yes" ]; then
|
||||
SSPLIB=""
|
||||
fi
|
||||
info "winssl: Configure no-shared $sslflags"
|
||||
set -x # echo the configure command
|
||||
__CNF_LDLIBS=$SSPLIB CC=${warch}-w64-mingw32-gcc AR=${warch}-w64-mingw32-ar RANLIB=${warch}-w64-mingw32-ranlib WINDRES=${warch}-w64-mingw32-windres ./Configure --prefix="$sslinstall" no-shared $sslflags || error_cleanup "OpenSSL Configure failed"
|
||||
set +x
|
||||
if test "$W64" = "no"; then
|
||||
# Disable stack-protector for 32-bit windows builds.
|
||||
# mingw passes an LDFLAGS, so there is something
|
||||
# passed in the LDFLAGS to stop -lssp passed in it.
|
||||
set -x # echo the configure command
|
||||
__CNF_LDLIBS=$SSPLIB __CNF_LDFLAGS="-fno-stack-protector" CC=${warch}-w64-mingw32-gcc AR=${warch}-w64-mingw32-ar RANLIB=${warch}-w64-mingw32-ranlib WINDRES=${warch}-w64-mingw32-windres ./Configure --prefix="$sslinstall" no-shared $sslflags || error_cleanup "OpenSSL Configure failed"
|
||||
set +x
|
||||
else
|
||||
set -x # echo the configure command
|
||||
__CNF_LDLIBS=$SSPLIB CC=${warch}-w64-mingw32-gcc AR=${warch}-w64-mingw32-ar RANLIB=${warch}-w64-mingw32-ranlib WINDRES=${warch}-w64-mingw32-windres ./Configure --prefix="$sslinstall" no-shared $sslflags || error_cleanup "OpenSSL Configure failed"
|
||||
set +x
|
||||
fi
|
||||
info "winssl: make"
|
||||
make $MINJ || error_cleanup "OpenSSL crosscompile failed"
|
||||
# only install sw not docs, which take a long time.
|
||||
@@ -297,9 +345,15 @@ if [ "$DOWIN" = "yes" ]; then
|
||||
sslsharedinstall="`pwd`/sslsharedinstall"
|
||||
cd openssl_shared
|
||||
info "winssl: Configure shared $sslflags"
|
||||
set -x # echo the configure command
|
||||
__CNF_LDLIBS=$SSPLIB CC=${warch}-w64-mingw32-gcc AR=${warch}-w64-mingw32-ar RANLIB=${warch}-w64-mingw32-ranlib WINDRES=${warch}-w64-mingw32-windres ./Configure --prefix="$sslsharedinstall" shared $sslflags || error_cleanup "OpenSSL Configure failed"
|
||||
set +x
|
||||
if test "$W64" = "no"; then
|
||||
set -x # echo the configure command
|
||||
__CNF_LDLIBS=$SSPLIB __CNF_LDFLAGS="-fno-stack-protector" CC=${warch}-w64-mingw32-gcc AR=${warch}-w64-mingw32-ar RANLIB=${warch}-w64-mingw32-ranlib WINDRES=${warch}-w64-mingw32-windres ./Configure --prefix="$sslsharedinstall" shared $sslflags || error_cleanup "OpenSSL Configure failed"
|
||||
set +x
|
||||
else
|
||||
set -x # echo the configure command
|
||||
__CNF_LDLIBS=$SSPLIB CC=${warch}-w64-mingw32-gcc AR=${warch}-w64-mingw32-ar RANLIB=${warch}-w64-mingw32-ranlib WINDRES=${warch}-w64-mingw32-windres ./Configure --prefix="$sslsharedinstall" shared $sslflags || error_cleanup "OpenSSL Configure failed"
|
||||
set +x
|
||||
fi
|
||||
info "winssl: make"
|
||||
make $MINJ || error_cleanup "OpenSSL crosscompile failed"
|
||||
info "winssl: make install_sw"
|
||||
@@ -308,6 +362,17 @@ if [ "$DOWIN" = "yes" ]; then
|
||||
cd ..
|
||||
fi
|
||||
|
||||
if test -n "$WINEXPAT" \
|
||||
-a -n "$WINDIR" \
|
||||
-a -d "$WINDIR" \
|
||||
-a -d "${WINDIR}/wxpinstall"; then
|
||||
info "Found already compiled expat at $WINDIR/wxpinstall; using that."
|
||||
WINEXPAT=""
|
||||
# Variables needed later on.
|
||||
wxpinstall="${WINDIR}/wxpinstall"
|
||||
cross_flag="$cross_flag --with-libexpat=$wxpinstall"
|
||||
shared_cross_flag="$shared_cross_flag --with-libexpat=$wxpinstall"
|
||||
fi
|
||||
if test -n "$WINEXPAT"; then
|
||||
info "Cross compile $WINEXPAT"
|
||||
info "wxp: tar unpack"
|
||||
@@ -315,7 +380,16 @@ if [ "$DOWIN" = "yes" ]; then
|
||||
wxpinstall="`pwd`/wxpinstall"
|
||||
cd expat-* || error_cleanup "no expat-X dir in tarball"
|
||||
info "wxp: configure"
|
||||
$configure --prefix="$wxpinstall" --exec-prefix="$wxpinstall" --bindir="$wxpinstall/bin" --includedir="$wxpinstall/include" --mandir="$wxpinstall/man" --libdir="$wxpinstall/lib" || error_cleanup "libexpat configure failed"
|
||||
if test "$W64" = "no"; then
|
||||
# Disable stack-protector for 32-bit windows builds.
|
||||
set -x # echo the configure command
|
||||
$configure --prefix="$wxpinstall" --exec-prefix="$wxpinstall" --bindir="$wxpinstall/bin" --includedir="$wxpinstall/include" --mandir="$wxpinstall/man" --libdir="$wxpinstall/lib" LDFLAGS="-fno-stack-protector" || error_cleanup "libexpat configure failed"
|
||||
set +x
|
||||
else
|
||||
set -x # echo the configure command
|
||||
$configure --prefix="$wxpinstall" --exec-prefix="$wxpinstall" --bindir="$wxpinstall/bin" --includedir="$wxpinstall/include" --mandir="$wxpinstall/man" --libdir="$wxpinstall/lib" || error_cleanup "libexpat configure failed"
|
||||
set +x
|
||||
fi
|
||||
info "wxp: make"
|
||||
make $MINJ || error_cleanup "libexpat crosscompile failed"
|
||||
info "wxp: make install"
|
||||
@@ -325,8 +399,12 @@ if [ "$DOWIN" = "yes" ]; then
|
||||
cd ..
|
||||
fi
|
||||
|
||||
info "GITREPO is $GITREPO"
|
||||
info "GITBRANCH is $GITBRANCH"
|
||||
if test -n "$WINDIR"; then
|
||||
cd "$cwd"
|
||||
create_temp_dir
|
||||
fi
|
||||
info "GITREPO is $GITREPO"
|
||||
info "GITBRANCH is $GITBRANCH"
|
||||
info "Exporting source from git."
|
||||
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"
|
||||
@@ -358,13 +436,17 @@ if [ "$DOWIN" = "yes" ]; then
|
||||
replace_version "configure.ac" "$version" "$version2"
|
||||
version="$version2"
|
||||
info "Rebuilding configure script (autoconf) snapshot."
|
||||
autoconf || error_cleanup "Autoconf failed."
|
||||
autoheader || error_cleanup "Autoheader 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."
|
||||
fi
|
||||
|
||||
if test "`uname`" = "Linux"; then
|
||||
(cd ..; cp -r unbound unbound_shared)
|
||||
cd ..
|
||||
cp -r unbound unbound_shared
|
||||
unbound_shared="`pwd`/unbound_shared"
|
||||
cd unbound
|
||||
fi
|
||||
|
||||
# procedure for making unbound installer on mingw.
|
||||
@@ -378,13 +460,15 @@ if [ "$DOWIN" = "yes" ]; then
|
||||
fi
|
||||
if test "$W64" = "no"; then
|
||||
# Disable stack-protector for 32-bit windows builds.
|
||||
echo "$configure"' --enable-debug --enable-static-exe --disable-flto --disable-gost '"$* $cross_flag" "$file_flag" "$file2_flag" "$file3_flag" CFLAGS='-O2 -g -fno-stack-protector'
|
||||
$configure --enable-debug --enable-static-exe --disable-flto --disable-gost $* $cross_flag "$file_flag" "$file2_flag" "$file3_flag" CFLAGS='-O2 -g -fno-stack-protector'\
|
||||
set -x
|
||||
$configure --enable-debug --enable-static-exe --disable-flto --disable-gost $* $cross_flag "$file_flag" "$file2_flag" "$file3_flag" CFLAGS='-O2 -g -fno-stack-protector' LDFLAGS="-fno-stack-protector" \
|
||||
|| error_cleanup "Could not configure"
|
||||
set +x
|
||||
else
|
||||
echo "$configure"' --enable-debug --enable-static-exe --disable-flto --disable-gost '"$* $cross_flag"
|
||||
set -x
|
||||
$configure --enable-debug --enable-static-exe --disable-flto --disable-gost $* $cross_flag \
|
||||
|| error_cleanup "Could not configure"
|
||||
set +x
|
||||
fi
|
||||
info "Calling make"
|
||||
make $MINJ || error_cleanup "Could not make"
|
||||
@@ -392,16 +476,18 @@ if [ "$DOWIN" = "yes" ]; then
|
||||
|
||||
if test "`uname`" = "Linux"; then
|
||||
info "Make DLL"
|
||||
cd ../unbound_shared
|
||||
cd $unbound_shared
|
||||
if test "$W64" = "no"; then
|
||||
# Disable stack-protector for 32-bit windows builds.
|
||||
echo "$configure"' --enable-debug --disable-flto --disable-gost '"$* $shared_cross_flag" "$file_flag" "$file2_flag" "$file3_flag" CFLAGS='-O2 -g -fno-stack-protector'
|
||||
$configure --enable-debug --disable-flto --disable-gost $* $shared_cross_flag "$file_flag" "$file2_flag" "$file3_flag" CFLAGS='-O2 -g -fno-stack-protector'\
|
||||
set -x
|
||||
$configure --enable-debug --disable-flto --disable-gost $* $shared_cross_flag "$file_flag" "$file2_flag" "$file3_flag" CFLAGS='-O2 -g -fno-stack-protector' LDFLAGS="-fno-stack-protector" \
|
||||
|| error_cleanup "Could not configure"
|
||||
set +x
|
||||
else
|
||||
echo "$configure"' --enable-debug --disable-flto --disable-gost '"$* $shared_cross_flag"
|
||||
$configure --enable-debug --disable-flto --disable-gost $* $shared_cross_flag \
|
||||
set -x
|
||||
$configure --enable-debug --disable-flto --disable-gost $* $shared_cross_flag \
|
||||
|| error_cleanup "Could not configure"
|
||||
set +x
|
||||
fi
|
||||
info "Calling make for DLL"
|
||||
make $MINJ || error_cleanup "Could not make DLL"
|
||||
@@ -430,17 +516,26 @@ if [ "$DOWIN" = "yes" ]; then
|
||||
cp ../unbound.exe ../unbound-anchor.exe ../unbound-host.exe ../unbound-control.exe ../unbound-checkconf.exe ../unbound-service-install.exe ../unbound-service-remove.exe ../LICENSE ../winrc/unbound-control-setup.cmd ../winrc/unbound-website.url ../winrc/service.conf ../winrc/README.txt ../contrib/create_unbound_ad_servers.cmd ../contrib/warmup.cmd ../contrib/unbound_cache.cmd .
|
||||
mkdir libunbound
|
||||
# test to see if lib or lib64 (for openssl 3.0.0) needs to be used
|
||||
if test -f ../../sslsharedinstall/lib/libcrypto.dll.a; then
|
||||
cp ../../sslsharedinstall/lib/libcrypto.dll.a libunbound/.
|
||||
if test -f $sslsharedinstall/lib/libcrypto.dll.a; then
|
||||
cp $sslsharedinstall/lib/libcrypto.dll.a libunbound/.
|
||||
else
|
||||
cp ../../sslsharedinstall/lib64/libcrypto.dll.a libunbound/.
|
||||
cp $sslsharedinstall/lib64/libcrypto.dll.a libunbound/.
|
||||
fi
|
||||
if test -f ../../sslsharedinstall/lib/libssl.dll.a; then
|
||||
cp ../../sslsharedinstall/lib/libssl.dll.a libunbound/.
|
||||
if test -f $sslsharedinstall/lib/libssl.dll.a; then
|
||||
cp $sslsharedinstall/lib/libssl.dll.a libunbound/.
|
||||
else
|
||||
cp ../../sslsharedinstall/lib64/libssl.dll.a libunbound/.
|
||||
cp $sslsharedinstall/lib64/libssl.dll.a libunbound/.
|
||||
fi
|
||||
cp ../../unbound_shared/unbound.h ../../unbound_shared/.libs/libunbound*.dll ../../unbound_shared/.libs/libunbound.dll.a ../../unbound_shared/.libs/libunbound.a ../../unbound_shared/.libs/libunbound*.def ../../sslsharedinstall/bin/libcrypto*.dll ../../sslsharedinstall/bin/libssl*.dll ../../wxpinstall/bin/libexpat*.dll ../../wxpinstall/lib/libexpat.dll.a libunbound/.
|
||||
cp $unbound_shared/unbound.h \
|
||||
$unbound_shared/.libs/libunbound*.dll \
|
||||
$unbound_shared/.libs/libunbound.dll.a \
|
||||
$unbound_shared/.libs/libunbound.a \
|
||||
$unbound_shared/.libs/libunbound*.def \
|
||||
$sslsharedinstall/bin/libcrypto*.dll \
|
||||
$sslsharedinstall/bin/libssl*.dll \
|
||||
$wxpinstall/bin/libexpat*.dll \
|
||||
$wxpinstall/lib/libexpat.dll.a \
|
||||
libunbound/.
|
||||
if test -f "$sspdll"; then
|
||||
cp "$sspdll" libunbound/.
|
||||
fi
|
||||
@@ -470,6 +565,11 @@ if [ "$DOWIN" = "yes" ]; then
|
||||
storehash unbound-$version.zip
|
||||
ls -lG unbound_setup_$version.exe
|
||||
ls -lG unbound-$version.zip
|
||||
|
||||
echo "create signed versions with:"
|
||||
echo " gpg --armor --detach-sign --digest-algo SHA256 unbound_setup_$version.exe"
|
||||
echo " gpg --armor --detach-sign --digest-algo SHA256 unbound-$version.zip"
|
||||
|
||||
info "Done"
|
||||
exit 0
|
||||
fi
|
||||
@@ -511,9 +611,10 @@ if [ `uname -s | grep -i -c darwin` -ne 0 ]; then
|
||||
fi
|
||||
|
||||
info "Building configure script (autoreconf)."
|
||||
autoreconf || 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."
|
||||
|
||||
info "Building lexer and parser."
|
||||
echo "#include \"config.h\"" > util/configlexer.c || error_cleanup "Failed to create configlexer"
|
||||
@@ -556,8 +657,9 @@ fi
|
||||
|
||||
if [ "$RECONFIGURE" = "yes" ]; then
|
||||
info "Rebuilding configure script (autoconf) snapshot."
|
||||
autoreconf || 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."
|
||||
fi
|
||||
|
||||
replace_all doc/README
|
||||
|
||||
@@ -1,9 +1,9 @@
|
||||
def init(id, cfg):
|
||||
log_info("pythonmod: init called, module id is %d port: %d script: %s" % (id, cfg.port, cfg.python_script))
|
||||
log_info("pythonmod: init called, module id is %d port: %d script: %s" % (id, cfg.port, mod_env['script']))
|
||||
return True
|
||||
|
||||
def init_standard(id, env):
|
||||
log_info("pythonmod: init called, module id is %d port: %d script: %s" % (id, env.cfg.port, env.cfg.python_script))
|
||||
log_info("pythonmod: init called, module id is %d port: %d script: %s" % (id, env.cfg.port, mod_env['script']))
|
||||
return True
|
||||
|
||||
def deinit(id):
|
||||
|
||||
@@ -50,7 +50,7 @@ Script file must contain four compulsory functions:
|
||||
::
|
||||
|
||||
def init(id, cfg):
|
||||
log_info("pythonmod: init called, module id is %d port: %d script: %s" % (id, cfg.port, cfg.python_script))
|
||||
log_info("pythonmod: init called, module id is %d port: %d script: %s" % (id, cfg.port, mod_env['script']))
|
||||
return True
|
||||
|
||||
|
||||
@@ -69,7 +69,7 @@ Script file must contain four compulsory functions:
|
||||
::
|
||||
|
||||
def init_standard(id, env):
|
||||
log_info("pythonmod: init called, module id is %d port: %d script: %s" % (id, env.cfg.port, env.cfg.python_script))
|
||||
log_info("pythonmod: init called, module id is %d port: %d script: %s" % (id, env.cfg.port, mod_env['script']))
|
||||
return True
|
||||
|
||||
|
||||
|
||||
@@ -129,7 +129,7 @@ config_file
|
||||
|
||||
.. attribute:: ifs
|
||||
|
||||
Interface description strings (IP addresses).
|
||||
List of interface description strings (IP addresses).
|
||||
|
||||
.. attribute:: num_out_ifs
|
||||
|
||||
@@ -138,7 +138,7 @@ config_file
|
||||
|
||||
.. attribute:: out_ifs
|
||||
|
||||
Outgoing interface description strings (IP addresses).
|
||||
List of outgoing interface description strings (IP addresses).
|
||||
|
||||
.. attribute:: root_hints
|
||||
|
||||
@@ -339,4 +339,5 @@ config_file
|
||||
|
||||
.. attribute:: python_script
|
||||
|
||||
Python script file.
|
||||
Linked list of Python script files.
|
||||
Deprecated; `mod_env['script']` should be used instead.
|
||||
|
||||
@@ -6,8 +6,11 @@ Global variables
|
||||
|
||||
.. envvar:: mod_env
|
||||
|
||||
Module environment, contains data pointer for module-specific data.
|
||||
See :class:`pythonmod_env`.
|
||||
Module environment, it is the 'data' pointer for module-specific data
|
||||
in :class:`pythonmod_env`.
|
||||
It is initialized as a dictionary with the 'script' key pointing to the
|
||||
module's python script.
|
||||
It can be further populated during runtime for module-specific data.
|
||||
|
||||
|
||||
Predefined constants
|
||||
|
||||
@@ -80,7 +80,7 @@ def init_standard(id, env):
|
||||
..note:: The previously accessible configuration options can now be found in
|
||||
env.cfg.
|
||||
"""
|
||||
log_info("python: inited script {}".format(env.cfg.python_script))
|
||||
log_info("python: inited script {}".format(mod_env['script']))
|
||||
|
||||
# Register EDNS option 65001 as a known EDNS option.
|
||||
if not register_edns_option(env, 65001, bypass_cache_stage=True,
|
||||
|
||||
@@ -287,7 +287,7 @@ def init_standard(id, env):
|
||||
env.cfg.
|
||||
|
||||
"""
|
||||
log_info("python: inited script {}".format(env.cfg.python_script))
|
||||
log_info("python: inited script {}".format(mod_env['script']))
|
||||
|
||||
# Register the inplace_reply_callback function as an inplace callback
|
||||
# function when answering a resolved query.
|
||||
|
||||
@@ -87,7 +87,7 @@ def logDnsMsg(qstate):
|
||||
print "-"*100
|
||||
|
||||
def init(id, cfg):
|
||||
log_info("pythonmod: init called, module id is %d port: %d script: %s" % (id, cfg.port, cfg.python_script))
|
||||
log_info("pythonmod: init called, module id is %d port: %d script: %s" % (id, cfg.port, mod_env['script']))
|
||||
return True
|
||||
|
||||
def deinit(id):
|
||||
|
||||
+43
-3
@@ -86,6 +86,20 @@
|
||||
}
|
||||
return list;
|
||||
}
|
||||
|
||||
/* converts an array of strings (char**) to a List of strings */
|
||||
PyObject* CharArrayAsStringList(char** array, int len) {
|
||||
PyObject* list;
|
||||
int i;
|
||||
|
||||
if(!array||len==0) return PyList_New(0);
|
||||
|
||||
list = PyList_New(len);
|
||||
for (i=0; i < len; i++) {
|
||||
PyList_SET_ITEM(list, i, PyString_FromString(array[i]));
|
||||
}
|
||||
return list;
|
||||
}
|
||||
%}
|
||||
|
||||
/* ************************************************************************************ *
|
||||
@@ -952,6 +966,9 @@ struct config_str2list {
|
||||
/* ************************************************************************************ *
|
||||
Structure config_file
|
||||
* ************************************************************************************ */
|
||||
%ignore config_file::ifs;
|
||||
%ignore config_file::out_ifs;
|
||||
%ignore config_file::python_script;
|
||||
struct config_file {
|
||||
int verbosity;
|
||||
int stat_interval;
|
||||
@@ -1035,6 +1052,25 @@ struct config_file {
|
||||
struct config_strlist* python_script;
|
||||
};
|
||||
|
||||
%inline %{
|
||||
PyObject* _get_ifs_tuple(struct config_file* cfg) {
|
||||
return CharArrayAsStringList(cfg->ifs, cfg->num_ifs);
|
||||
}
|
||||
PyObject* _get_ifs_out_tuple(struct config_file* cfg) {
|
||||
return CharArrayAsStringList(cfg->out_ifs, cfg->num_out_ifs);
|
||||
}
|
||||
%}
|
||||
|
||||
%extend config_file {
|
||||
%pythoncode %{
|
||||
ifs = property(_unboundmodule._get_ifs_tuple)
|
||||
out_ifs = property(_unboundmodule._get_ifs_out_tuple)
|
||||
|
||||
def _deprecated_python_script(self): return "cfg.python_script is deprecated, you can use `mod_env['script']` instead."
|
||||
python_script = property(_deprecated_python_script)
|
||||
%}
|
||||
}
|
||||
|
||||
/* ************************************************************************************ *
|
||||
ASN: Adding structures related to forwards_lookup and dns_cache_find_delegation
|
||||
* ************************************************************************************ */
|
||||
@@ -1380,7 +1416,7 @@ struct delegpt* dns_cache_find_delegation(struct module_env* env,
|
||||
int iter_dp_is_useless(struct query_info* qinfo, uint16_t qflags,
|
||||
struct delegpt* dp, int supports_ipv4, int supports_ipv6, int use_nat64);
|
||||
struct iter_hints_stub* hints_lookup_stub(struct iter_hints* hints,
|
||||
uint8_t* qname, uint16_t qclass, struct delegpt* dp);
|
||||
uint8_t* qname, uint16_t qclass, struct delegpt* dp, int nolock);
|
||||
|
||||
/* Custom function to perform logic similar to the one in daemon/cachedump.c */
|
||||
struct delegpt* find_delegation(struct module_qstate* qstate, char *nm, size_t nmlen);
|
||||
@@ -1397,6 +1433,7 @@ struct delegpt* find_delegation(struct module_qstate* qstate, char *nm, size_t n
|
||||
struct query_info qinfo;
|
||||
struct iter_hints_stub* stub;
|
||||
uint32_t timenow = *qstate->env->now;
|
||||
int nolock = 0;
|
||||
|
||||
regional_free_all(region);
|
||||
qinfo.qname = (uint8_t*)nm;
|
||||
@@ -1419,9 +1456,12 @@ struct delegpt* find_delegation(struct module_qstate* qstate, char *nm, size_t n
|
||||
dname_str((uint8_t*)nm, b);
|
||||
continue;
|
||||
}
|
||||
stub = hints_lookup_stub(qstate->env->hints, qinfo.qname, qinfo.qclass, dp);
|
||||
stub = hints_lookup_stub(qstate->env->hints, qinfo.qname,
|
||||
qinfo.qclass, dp, nolock);
|
||||
if (stub) {
|
||||
return stub->dp;
|
||||
struct delegpt* stubdp = delegpt_copy(stub->dp, region);
|
||||
lock_rw_unlock(&qstate->env->hints->lock);
|
||||
return stubdp;
|
||||
} else {
|
||||
return dp;
|
||||
}
|
||||
|
||||
+42
-4
@@ -112,6 +112,34 @@ struct pythonmod_qstate {
|
||||
PyObject* data;
|
||||
};
|
||||
|
||||
/* The dict from __main__ could have remnants from a previous script
|
||||
* invocation, in a multi python module setup. Usually this is fine since newer
|
||||
* scripts will update their values. The obvious erroneous case is when mixing
|
||||
* python scripts that make use of both 'init' and 'init_standard'. This
|
||||
* results in 'init_standard' to persist on following scripts that don't use it
|
||||
* (thus not replacing it). This is also problematic in case where a script
|
||||
* does not define a required function but a previously loaded script did. The
|
||||
* current solution is to make sure to clean offensive remnants that influence
|
||||
* further parsing of the individual scripts.
|
||||
*/
|
||||
static void
|
||||
clean_python_function_objects(PyObject* dict) {
|
||||
const char* function_names[] = {
|
||||
"init",
|
||||
"init_standard",
|
||||
"deinit",
|
||||
"operate",
|
||||
"inform_super"
|
||||
};
|
||||
size_t i;
|
||||
|
||||
for(i=0; i<sizeof(function_names)/sizeof(function_names[0]); i++) {
|
||||
if(PyDict_GetItemString(dict, function_names[i]) != NULL) {
|
||||
PyDict_DelItemString(dict, function_names[i]);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
/* Generated */
|
||||
#ifndef S_SPLINT_S
|
||||
#include "pythonmod/interface.h"
|
||||
@@ -269,7 +297,7 @@ int pythonmod_init(struct module_env* env, int id)
|
||||
|
||||
/* Initialize module */
|
||||
FILE* script_py = NULL;
|
||||
PyObject* py_init_arg = NULL, *res = NULL;
|
||||
PyObject* py_init_arg = NULL, *res = NULL, *fname = NULL;
|
||||
PyGILState_STATE gil;
|
||||
int init_standard = 1, i = 0;
|
||||
#if PY_MAJOR_VERSION < 3
|
||||
@@ -328,11 +356,11 @@ int pythonmod_init(struct module_env* env, int id)
|
||||
return 0;
|
||||
}
|
||||
#endif
|
||||
Py_NoSiteFlag = 1;
|
||||
#if PY_MAJOR_VERSION >= 3
|
||||
PyImport_AppendInittab(SWIG_name, (void*)SWIG_init);
|
||||
#endif
|
||||
#if PY_VERSION_HEX < 0x03080000
|
||||
Py_NoSiteFlag = 1;
|
||||
Py_Initialize();
|
||||
#else
|
||||
PyConfig_InitPythonConfig(&config);
|
||||
@@ -418,7 +446,17 @@ int pythonmod_init(struct module_env* env, int id)
|
||||
Py_XINCREF(pe->module);
|
||||
pe->dict = PyModule_GetDict(pe->module);
|
||||
Py_XINCREF(pe->dict);
|
||||
clean_python_function_objects(pe->dict);
|
||||
|
||||
pe->data = PyDict_New();
|
||||
/* add the script filename to the global "mod_env" for trivial access */
|
||||
fname = PyString_FromString(pe->fname);
|
||||
if(PyDict_SetItemString(pe->data, "script", fname) < 0) {
|
||||
log_err("pythonmod: could not add item to dictionary");
|
||||
Py_XDECREF(fname);
|
||||
goto python_init_fail;
|
||||
}
|
||||
Py_XDECREF(fname);
|
||||
Py_XINCREF(pe->data); /* reference will be stolen below */
|
||||
if(PyModule_AddObject(pe->module, "mod_env", pe->data) < 0) {
|
||||
log_err("pythonmod: could not add mod_env object");
|
||||
@@ -739,8 +777,8 @@ size_t pythonmod_get_mem(struct module_env* env, int id)
|
||||
*/
|
||||
static struct module_func_block pythonmod_block = {
|
||||
"python",
|
||||
&pythonmod_init, &pythonmod_deinit, &pythonmod_operate, &pythonmod_inform_super,
|
||||
&pythonmod_clear, &pythonmod_get_mem
|
||||
NULL, NULL, &pythonmod_init, &pythonmod_deinit, &pythonmod_operate,
|
||||
&pythonmod_inform_super, &pythonmod_clear, &pythonmod_get_mem
|
||||
};
|
||||
|
||||
struct module_func_block* pythonmod_get_funcblock(void)
|
||||
|
||||
@@ -35,7 +35,7 @@
|
||||
import os
|
||||
|
||||
def init(id, cfg):
|
||||
log_info("pythonmod: init called, module id is %d port: %d script: %s" % (id, cfg.port, cfg.python_script))
|
||||
log_info("pythonmod: init called, module id is %d port: %d script: %s" % (id, cfg.port, mod_env['script']))
|
||||
return True
|
||||
|
||||
def deinit(id):
|
||||
|
||||
+21
-18
@@ -33,7 +33,7 @@
|
||||
POSSIBILITY OF SUCH DAMAGE.
|
||||
'''
|
||||
def init(id, cfg):
|
||||
log_info("pythonmod: init called, module id is %d port: %d script: %s" % (id, cfg.port, cfg.python_script))
|
||||
log_info("pythonmod: init called, module id is %d port: %d script: %s" % (id, cfg.port, mod_env['script']))
|
||||
return True
|
||||
|
||||
def deinit(id):
|
||||
@@ -55,12 +55,15 @@ def setTTL(qstate, ttl):
|
||||
|
||||
def dataHex(data, prefix=""):
|
||||
res = ""
|
||||
for i in range(0, (len(data)+15)/16):
|
||||
for i in range(0, int((len(data)+15)/16)):
|
||||
res += "%s0x%02X | " % (prefix, i*16)
|
||||
d = map(lambda x:ord(x), data[i*16:i*16+17])
|
||||
if type(data[0]) == type(1):
|
||||
d = map(lambda x:int(x), data[i*16:i*16+17])
|
||||
else:
|
||||
d = map(lambda x:ord(x), data[i*16:i*16+17])
|
||||
for ch in d:
|
||||
res += "%02X " % ch
|
||||
for i in range(0,17-len(d)):
|
||||
for i in range(0,17-len(data[i*16:i*16+17])):
|
||||
res += " "
|
||||
res += "| "
|
||||
for ch in d:
|
||||
@@ -72,31 +75,31 @@ def dataHex(data, prefix=""):
|
||||
return res
|
||||
|
||||
def printReturnMsg(qstate):
|
||||
print "Return MSG rep :: flags: %04X, QDcount: %d, Security:%d, TTL=%d" % (qstate.return_msg.rep.flags, qstate.return_msg.rep.qdcount,qstate.return_msg.rep.security, qstate.return_msg.rep.ttl)
|
||||
print " qinfo :: qname:",qstate.return_msg.qinfo.qname_list, qstate.return_msg.qinfo.qname_str, "type:",qstate.return_msg.qinfo.qtype_str, "class:",qstate.return_msg.qinfo.qclass_str
|
||||
print("Return MSG rep :: flags: %04X, QDcount: %d, Security:%d, TTL=%d" % (qstate.return_msg.rep.flags, qstate.return_msg.rep.qdcount,qstate.return_msg.rep.security, qstate.return_msg.rep.ttl))
|
||||
print(" qinfo :: qname:",qstate.return_msg.qinfo.qname_list, qstate.return_msg.qinfo.qname_str, "type:",qstate.return_msg.qinfo.qtype_str, "class:",qstate.return_msg.qinfo.qclass_str)
|
||||
if (qstate.return_msg.rep):
|
||||
print "RRSets:",qstate.return_msg.rep.rrset_count
|
||||
print("RRSets:",qstate.return_msg.rep.rrset_count)
|
||||
prevkey = None
|
||||
for i in range(0,qstate.return_msg.rep.rrset_count):
|
||||
r = qstate.return_msg.rep.rrsets[i]
|
||||
rk = r.rk
|
||||
print i,":",rk.dname_list, rk.dname_str, "flags: %04X" % rk.flags,
|
||||
print "type:",rk.type_str,"(%d)" % ntohs(rk.type), "class:",rk.rrset_class_str,"(%d)" % ntohs(rk.rrset_class)
|
||||
print(i,":",rk.dname_list, rk.dname_str, "flags: %04X" % rk.flags)
|
||||
print("type:",rk.type_str,"(%d)" % ntohs(rk.type), "class:",rk.rrset_class_str,"(%d)" % ntohs(rk.rrset_class))
|
||||
|
||||
d = r.entry.data
|
||||
print " RRDatas:",d.count+d.rrsig_count
|
||||
print(" RRDatas:",d.count+d.rrsig_count)
|
||||
for j in range(0,d.count+d.rrsig_count):
|
||||
print " ",j,":","TTL=",d.rr_ttl[j],"RR data:"
|
||||
print dataHex(d.rr_data[j]," ")
|
||||
print(" ",j,":","TTL=",d.rr_ttl[j],"RR data:")
|
||||
print(dataHex(d.rr_data[j]," "))
|
||||
|
||||
def operate(id, event, qstate, qdata):
|
||||
log_info("pythonmod: operate called, id: %d, event:%s" % (id, strmodulevent(event)))
|
||||
#print "pythonmod: per query data", qdata
|
||||
#print("pythonmod: per query data", qdata)
|
||||
|
||||
print "Query:", ''.join(map(lambda x:chr(max(32,ord(x))),qstate.qinfo.qname)), qstate.qinfo.qname_list,
|
||||
print "Type:",qstate.qinfo.qtype_str,"(%d)" % qstate.qinfo.qtype,
|
||||
print "Class:",qstate.qinfo.qclass_str,"(%d)" % qstate.qinfo.qclass
|
||||
print
|
||||
print("Query:", qstate.qinfo.qname, qstate.qinfo.qname_list, qstate.qinfo.qname_str)
|
||||
print("Type:",qstate.qinfo.qtype_str,"(%d)" % qstate.qinfo.qtype)
|
||||
print("Class:",qstate.qinfo.qclass_str,"(%d)" % qstate.qinfo.qclass)
|
||||
print("")
|
||||
|
||||
# TEST:
|
||||
# > dig @127.0.0.1 www.seznam.cz A
|
||||
@@ -118,7 +121,7 @@ def operate(id, event, qstate, qdata):
|
||||
invalidateQueryInCache(qstate, qstate.return_msg.qinfo)
|
||||
|
||||
if (qstate.return_msg.rep.authoritative):
|
||||
print "X"*300
|
||||
print("X"*300)
|
||||
|
||||
setTTL(qstate, 10) #do cache nastavime TTL na 10
|
||||
if not storeQueryInCache(qstate, qstate.return_msg.qinfo, qstate.return_msg.rep, 0):
|
||||
|
||||
+2
-2
@@ -1259,8 +1259,8 @@ respip_get_mem(struct module_env* env, int id)
|
||||
*/
|
||||
static struct module_func_block respip_block = {
|
||||
"respip",
|
||||
&respip_init, &respip_deinit, &respip_operate, &respip_inform_super,
|
||||
&respip_clear, &respip_get_mem
|
||||
NULL, NULL, &respip_init, &respip_deinit, &respip_operate,
|
||||
&respip_inform_super, &respip_clear, &respip_get_mem
|
||||
};
|
||||
|
||||
struct module_func_block*
|
||||
|
||||
+49
-21
@@ -2152,6 +2152,16 @@ auth_zones_cfg(struct auth_zones* az, struct config_auth* c)
|
||||
if(az->rpz_first)
|
||||
az->rpz_first->rpz_az_prev = z;
|
||||
az->rpz_first = z;
|
||||
} else if(c->isrpz && z->rpz) {
|
||||
if(!rpz_config(z->rpz, c)) {
|
||||
log_err("Could not change rpz config");
|
||||
if(x) {
|
||||
lock_basic_unlock(&x->lock);
|
||||
}
|
||||
lock_rw_unlock(&z->lock);
|
||||
lock_rw_unlock(&az->rpz_lock);
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
if(c->isrpz) {
|
||||
lock_rw_unlock(&az->rpz_lock);
|
||||
@@ -2475,6 +2485,7 @@ az_find_ce(struct auth_zone* z, struct query_info* qinfo,
|
||||
struct auth_rrset** rrset)
|
||||
{
|
||||
struct auth_data* n = node;
|
||||
struct auth_rrset* lookrrset;
|
||||
*ce = NULL;
|
||||
*rrset = NULL;
|
||||
if(!node_exact) {
|
||||
@@ -2497,21 +2508,23 @@ az_find_ce(struct auth_zone* z, struct query_info* qinfo,
|
||||
/* see if the current candidate has issues */
|
||||
/* not zone apex and has type NS */
|
||||
if(n->namelen != z->namelen &&
|
||||
(*rrset=az_domain_rrset(n, LDNS_RR_TYPE_NS)) &&
|
||||
(lookrrset=az_domain_rrset(n, LDNS_RR_TYPE_NS)) &&
|
||||
/* delegate here, but DS at exact the dp has notype */
|
||||
(qinfo->qtype != LDNS_RR_TYPE_DS ||
|
||||
n->namelen != qinfo->qname_len)) {
|
||||
/* referral */
|
||||
/* this is ce and the lowernode is nonexisting */
|
||||
*ce = n;
|
||||
return 0;
|
||||
*rrset = lookrrset;
|
||||
node_exact = 0;
|
||||
}
|
||||
/* not equal to qname and has type DNAME */
|
||||
if(n->namelen != qinfo->qname_len &&
|
||||
(*rrset=az_domain_rrset(n, LDNS_RR_TYPE_DNAME))) {
|
||||
(lookrrset=az_domain_rrset(n, LDNS_RR_TYPE_DNAME))) {
|
||||
/* this is ce and the lowernode is nonexisting */
|
||||
*ce = n;
|
||||
return 0;
|
||||
*rrset = lookrrset;
|
||||
node_exact = 0;
|
||||
}
|
||||
|
||||
if(*ce == NULL && !domain_has_only_nsec3(n)) {
|
||||
@@ -2699,7 +2712,7 @@ create_synth_cname(uint8_t* qname, size_t qname_len, struct regional* region,
|
||||
if(!d)
|
||||
return 0; /* out of memory */
|
||||
(*cname)->entry.data = d;
|
||||
d->ttl = 0; /* 0 for synthesized CNAME TTL */
|
||||
d->ttl = dname->data->ttl; /* RFC6672: synth CNAME TTL == DNAME TTL */
|
||||
d->count = 1;
|
||||
d->rrsig_count = 0;
|
||||
d->trust = rrset_trust_ans_noAA;
|
||||
@@ -7765,12 +7778,14 @@ static void auth_zone_log(uint8_t* name, enum verbosity_value level,
|
||||
static int zonemd_dnssec_verify_rrset(struct auth_zone* z,
|
||||
struct module_env* env, struct module_stack* mods,
|
||||
struct ub_packed_rrset_key* dnskey, struct auth_data* node,
|
||||
struct auth_rrset* rrset, char** why_bogus, uint8_t* sigalg)
|
||||
struct auth_rrset* rrset, char** why_bogus, uint8_t* sigalg,
|
||||
char* reasonbuf, size_t reasonlen)
|
||||
{
|
||||
struct ub_packed_rrset_key pk;
|
||||
enum sec_status sec;
|
||||
struct val_env* ve;
|
||||
int m;
|
||||
int verified = 0;
|
||||
m = modstack_find(mods, "validator");
|
||||
if(m == -1) {
|
||||
auth_zone_log(z->name, VERB_ALGO, "zonemd dnssec verify: have "
|
||||
@@ -7794,7 +7809,7 @@ static int zonemd_dnssec_verify_rrset(struct auth_zone* z,
|
||||
"zonemd: verify %s RRset with DNSKEY", typestr);
|
||||
}
|
||||
sec = dnskeyset_verify_rrset(env, ve, &pk, dnskey, sigalg, why_bogus, NULL,
|
||||
LDNS_SECTION_ANSWER, NULL);
|
||||
LDNS_SECTION_ANSWER, NULL, &verified, reasonbuf, reasonlen);
|
||||
if(sec == sec_status_secure) {
|
||||
return 1;
|
||||
}
|
||||
@@ -7837,7 +7852,8 @@ static int nsec3_of_param_has_type(struct auth_rrset* nsec3, int algo,
|
||||
static int zonemd_check_dnssec_absence(struct auth_zone* z,
|
||||
struct module_env* env, struct module_stack* mods,
|
||||
struct ub_packed_rrset_key* dnskey, struct auth_data* apex,
|
||||
char** reason, char** why_bogus, uint8_t* sigalg)
|
||||
char** reason, char** why_bogus, uint8_t* sigalg, char* reasonbuf,
|
||||
size_t reasonlen)
|
||||
{
|
||||
struct auth_rrset* nsec = NULL;
|
||||
if(!apex) {
|
||||
@@ -7849,7 +7865,7 @@ static int zonemd_check_dnssec_absence(struct auth_zone* z,
|
||||
struct ub_packed_rrset_key pk;
|
||||
/* dnssec verify the NSEC */
|
||||
if(!zonemd_dnssec_verify_rrset(z, env, mods, dnskey, apex,
|
||||
nsec, why_bogus, sigalg)) {
|
||||
nsec, why_bogus, sigalg, reasonbuf, reasonlen)) {
|
||||
*reason = "DNSSEC verify failed for NSEC RRset";
|
||||
return 0;
|
||||
}
|
||||
@@ -7892,7 +7908,7 @@ static int zonemd_check_dnssec_absence(struct auth_zone* z,
|
||||
}
|
||||
/* dnssec verify the NSEC3 */
|
||||
if(!zonemd_dnssec_verify_rrset(z, env, mods, dnskey, match,
|
||||
nsec3, why_bogus, sigalg)) {
|
||||
nsec3, why_bogus, sigalg, reasonbuf, reasonlen)) {
|
||||
*reason = "DNSSEC verify failed for NSEC3 RRset";
|
||||
return 0;
|
||||
}
|
||||
@@ -7914,7 +7930,7 @@ static int zonemd_check_dnssec_soazonemd(struct auth_zone* z,
|
||||
struct module_env* env, struct module_stack* mods,
|
||||
struct ub_packed_rrset_key* dnskey, struct auth_data* apex,
|
||||
struct auth_rrset* zonemd_rrset, char** reason, char** why_bogus,
|
||||
uint8_t* sigalg)
|
||||
uint8_t* sigalg, char* reasonbuf, size_t reasonlen)
|
||||
{
|
||||
struct auth_rrset* soa;
|
||||
if(!apex) {
|
||||
@@ -7927,12 +7943,12 @@ static int zonemd_check_dnssec_soazonemd(struct auth_zone* z,
|
||||
return 0;
|
||||
}
|
||||
if(!zonemd_dnssec_verify_rrset(z, env, mods, dnskey, apex, soa,
|
||||
why_bogus, sigalg)) {
|
||||
why_bogus, sigalg, reasonbuf, reasonlen)) {
|
||||
*reason = "DNSSEC verify failed for SOA RRset";
|
||||
return 0;
|
||||
}
|
||||
if(!zonemd_dnssec_verify_rrset(z, env, mods, dnskey, apex,
|
||||
zonemd_rrset, why_bogus, sigalg)) {
|
||||
zonemd_rrset, why_bogus, sigalg, reasonbuf, reasonlen)) {
|
||||
*reason = "DNSSEC verify failed for ZONEMD RRset";
|
||||
return 0;
|
||||
}
|
||||
@@ -8000,6 +8016,7 @@ auth_zone_verify_zonemd_with_key(struct auth_zone* z, struct module_env* env,
|
||||
struct module_stack* mods, struct ub_packed_rrset_key* dnskey,
|
||||
int is_insecure, char** result, uint8_t* sigalg)
|
||||
{
|
||||
char reasonbuf[256];
|
||||
char* reason = NULL, *why_bogus = NULL;
|
||||
struct auth_data* apex = NULL;
|
||||
struct auth_rrset* zonemd_rrset = NULL;
|
||||
@@ -8028,7 +8045,8 @@ auth_zone_verify_zonemd_with_key(struct auth_zone* z, struct module_env* env,
|
||||
} else if(!zonemd_rrset && dnskey && !is_insecure) {
|
||||
/* fetch, DNSSEC verify, and check NSEC/NSEC3 */
|
||||
if(!zonemd_check_dnssec_absence(z, env, mods, dnskey, apex,
|
||||
&reason, &why_bogus, sigalg)) {
|
||||
&reason, &why_bogus, sigalg, reasonbuf,
|
||||
sizeof(reasonbuf))) {
|
||||
auth_zone_zonemd_fail(z, env, reason, why_bogus, result);
|
||||
return;
|
||||
}
|
||||
@@ -8036,7 +8054,8 @@ auth_zone_verify_zonemd_with_key(struct auth_zone* z, struct module_env* env,
|
||||
} else if(zonemd_rrset && dnskey && !is_insecure) {
|
||||
/* check DNSSEC verify of SOA and ZONEMD */
|
||||
if(!zonemd_check_dnssec_soazonemd(z, env, mods, dnskey, apex,
|
||||
zonemd_rrset, &reason, &why_bogus, sigalg)) {
|
||||
zonemd_rrset, &reason, &why_bogus, sigalg, reasonbuf,
|
||||
sizeof(reasonbuf))) {
|
||||
auth_zone_zonemd_fail(z, env, reason, why_bogus, result);
|
||||
return;
|
||||
}
|
||||
@@ -8100,7 +8119,8 @@ static struct ub_packed_rrset_key*
|
||||
zonemd_get_dnskey_from_anchor(struct auth_zone* z, struct module_env* env,
|
||||
struct module_stack* mods, struct trust_anchor* anchor,
|
||||
int* is_insecure, char** why_bogus,
|
||||
struct ub_packed_rrset_key* keystorage)
|
||||
struct ub_packed_rrset_key* keystorage, char* reasonbuf,
|
||||
size_t reasonlen)
|
||||
{
|
||||
struct auth_data* apex;
|
||||
struct auth_rrset* dnskey_rrset;
|
||||
@@ -8136,7 +8156,8 @@ zonemd_get_dnskey_from_anchor(struct auth_zone* z, struct module_env* env,
|
||||
auth_zone_log(z->name, VERB_QUERY,
|
||||
"zonemd: verify DNSKEY RRset with trust anchor");
|
||||
sec = val_verify_DNSKEY_with_TA(env, ve, keystorage, anchor->ds_rrset,
|
||||
anchor->dnskey_rrset, NULL, why_bogus, NULL, NULL);
|
||||
anchor->dnskey_rrset, NULL, why_bogus, NULL, NULL, reasonbuf,
|
||||
reasonlen);
|
||||
regional_free_all(env->scratch);
|
||||
if(sec == sec_status_secure) {
|
||||
/* success */
|
||||
@@ -8159,7 +8180,8 @@ static struct ub_packed_rrset_key*
|
||||
auth_zone_verify_zonemd_key_with_ds(struct auth_zone* z,
|
||||
struct module_env* env, struct module_stack* mods,
|
||||
struct ub_packed_rrset_key* ds, int* is_insecure, char** why_bogus,
|
||||
struct ub_packed_rrset_key* keystorage, uint8_t* sigalg)
|
||||
struct ub_packed_rrset_key* keystorage, uint8_t* sigalg,
|
||||
char* reasonbuf, size_t reasonlen)
|
||||
{
|
||||
struct auth_data* apex;
|
||||
struct auth_rrset* dnskey_rrset;
|
||||
@@ -8195,7 +8217,7 @@ auth_zone_verify_zonemd_key_with_ds(struct auth_zone* z,
|
||||
keystorage->rk.rrset_class = htons(z->dclass);
|
||||
auth_zone_log(z->name, VERB_QUERY, "zonemd: verify zone DNSKEY with DS");
|
||||
sec = val_verify_DNSKEY_with_DS(env, ve, keystorage, ds, sigalg,
|
||||
why_bogus, NULL, NULL);
|
||||
why_bogus, NULL, NULL, reasonbuf, reasonlen);
|
||||
regional_free_all(env->scratch);
|
||||
if(sec == sec_status_secure) {
|
||||
/* success */
|
||||
@@ -8221,6 +8243,7 @@ void auth_zonemd_dnskey_lookup_callback(void* arg, int rcode, sldns_buffer* buf,
|
||||
{
|
||||
struct auth_zone* z = (struct auth_zone*)arg;
|
||||
struct module_env* env;
|
||||
char reasonbuf[256];
|
||||
char* reason = NULL, *ds_bogus = NULL, *typestr="DNSKEY";
|
||||
struct ub_packed_rrset_key* dnskey = NULL, *ds = NULL;
|
||||
int is_insecure = 0, downprot;
|
||||
@@ -8332,7 +8355,8 @@ void auth_zonemd_dnskey_lookup_callback(void* arg, int rcode, sldns_buffer* buf,
|
||||
if(!reason && !is_insecure && !dnskey && ds) {
|
||||
dnskey = auth_zone_verify_zonemd_key_with_ds(z, env,
|
||||
&env->mesh->mods, ds, &is_insecure, &ds_bogus,
|
||||
&keystorage, downprot?sigalg:NULL);
|
||||
&keystorage, downprot?sigalg:NULL, reasonbuf,
|
||||
sizeof(reasonbuf));
|
||||
if(!dnskey && !is_insecure && !reason)
|
||||
reason = "DNSKEY verify with DS failed";
|
||||
}
|
||||
@@ -8340,6 +8364,7 @@ void auth_zonemd_dnskey_lookup_callback(void* arg, int rcode, sldns_buffer* buf,
|
||||
if(reason) {
|
||||
auth_zone_zonemd_fail(z, env, reason, ds_bogus, NULL);
|
||||
lock_rw_unlock(&z->lock);
|
||||
regional_free_all(env->scratch);
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -8424,6 +8449,7 @@ zonemd_lookup_dnskey(struct auth_zone* z, struct module_env* env)
|
||||
void auth_zone_verify_zonemd(struct auth_zone* z, struct module_env* env,
|
||||
struct module_stack* mods, char** result, int offline, int only_online)
|
||||
{
|
||||
char reasonbuf[256];
|
||||
char* reason = NULL, *why_bogus = NULL;
|
||||
struct trust_anchor* anchor = NULL;
|
||||
struct ub_packed_rrset_key* dnskey = NULL;
|
||||
@@ -8458,7 +8484,8 @@ void auth_zone_verify_zonemd(struct auth_zone* z, struct module_env* env,
|
||||
}
|
||||
/* equal to trustanchor, no need for online lookups */
|
||||
dnskey = zonemd_get_dnskey_from_anchor(z, env, mods, anchor,
|
||||
&is_insecure, &why_bogus, &keystorage);
|
||||
&is_insecure, &why_bogus, &keystorage, reasonbuf,
|
||||
sizeof(reasonbuf));
|
||||
lock_basic_unlock(&anchor->lock);
|
||||
if(!dnskey && !reason && !is_insecure) {
|
||||
reason = "verify DNSKEY RRset with trust anchor failed";
|
||||
@@ -8484,6 +8511,7 @@ void auth_zone_verify_zonemd(struct auth_zone* z, struct module_env* env,
|
||||
|
||||
if(reason) {
|
||||
auth_zone_zonemd_fail(z, env, reason, why_bogus, result);
|
||||
regional_free_all(env->scratch);
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
Vendored
+48
-48
@@ -80,6 +80,7 @@ store_rrsets(struct module_env* env, struct reply_info* rep, time_t now,
|
||||
struct regional* region, time_t qstarttime)
|
||||
{
|
||||
size_t i;
|
||||
time_t ttl, min_ttl = rep->ttl;
|
||||
/* see if rrset already exists in cache, if not insert it. */
|
||||
for(i=0; i<rep->rrset_count; i++) {
|
||||
rep->ref[i].key = rep->rrsets[i];
|
||||
@@ -95,7 +96,8 @@ store_rrsets(struct module_env* env, struct reply_info* rep, time_t now,
|
||||
struct ub_packed_rrset_key* ck;
|
||||
lock_rw_rdlock(&rep->ref[i].key->entry.lock);
|
||||
/* if deleted rrset, do not copy it */
|
||||
if(rep->ref[i].key->id == 0)
|
||||
if(rep->ref[i].key->id == 0 ||
|
||||
rep->ref[i].id != rep->ref[i].key->id)
|
||||
ck = NULL;
|
||||
else ck = packed_rrset_copy_region(
|
||||
rep->ref[i].key, region, now);
|
||||
@@ -111,8 +113,24 @@ store_rrsets(struct module_env* env, struct reply_info* rep, time_t now,
|
||||
/* fallthrough */
|
||||
case 1: /* ref updated, item inserted */
|
||||
rep->rrsets[i] = rep->ref[i].key;
|
||||
/* ref was updated; make sure the message ttl is
|
||||
* updated to the minimum of the current rrsets. */
|
||||
lock_rw_rdlock(&rep->ref[i].key->entry.lock);
|
||||
/* if deleted, skip ttl update. */
|
||||
if(rep->ref[i].key->id != 0 &&
|
||||
rep->ref[i].id == rep->ref[i].key->id) {
|
||||
ttl = ((struct packed_rrset_data*)
|
||||
rep->rrsets[i]->entry.data)->ttl;
|
||||
if(ttl < min_ttl) min_ttl = ttl;
|
||||
}
|
||||
lock_rw_unlock(&rep->ref[i].key->entry.lock);
|
||||
}
|
||||
}
|
||||
if(min_ttl < rep->ttl) {
|
||||
rep->ttl = min_ttl;
|
||||
rep->prefetch_ttl = PREFETCH_TTL_CALC(rep->ttl);
|
||||
rep->serve_expired_ttl = rep->ttl + SERVE_EXPIRED_TTL;
|
||||
}
|
||||
}
|
||||
|
||||
/** delete message from message cache */
|
||||
@@ -183,46 +201,6 @@ dns_cache_store_msg(struct module_env* env, struct query_info* qinfo,
|
||||
slabhash_insert(env->msg_cache, hash, &e->entry, rep, env->alloc);
|
||||
}
|
||||
|
||||
/** see if an rrset is expired above the qname, return upper qname. */
|
||||
static int
|
||||
rrset_expired_above(struct module_env* env, uint8_t** qname, size_t* qnamelen,
|
||||
uint16_t searchtype, uint16_t qclass, time_t now, uint8_t* expiretop,
|
||||
size_t expiretoplen)
|
||||
{
|
||||
struct ub_packed_rrset_key *rrset;
|
||||
uint8_t lablen;
|
||||
|
||||
while(*qnamelen > 0) {
|
||||
/* look one label higher */
|
||||
lablen = **qname;
|
||||
*qname += lablen + 1;
|
||||
*qnamelen -= lablen + 1;
|
||||
if(*qnamelen <= 0)
|
||||
break;
|
||||
|
||||
/* looks up with a time of 0, to see expired entries */
|
||||
if((rrset = rrset_cache_lookup(env->rrset_cache, *qname,
|
||||
*qnamelen, searchtype, qclass, 0, 0, 0))) {
|
||||
struct packed_rrset_data* data =
|
||||
(struct packed_rrset_data*)rrset->entry.data;
|
||||
if(now > data->ttl) {
|
||||
/* it is expired, this is not wanted */
|
||||
lock_rw_unlock(&rrset->entry.lock);
|
||||
log_nametypeclass(VERB_ALGO, "this rrset is expired", *qname, searchtype, qclass);
|
||||
return 1;
|
||||
}
|
||||
/* it is not expired, continue looking */
|
||||
lock_rw_unlock(&rrset->entry.lock);
|
||||
}
|
||||
|
||||
/* do not look above the expiretop. */
|
||||
if(expiretop && *qnamelen == expiretoplen &&
|
||||
query_dname_compare(*qname, expiretop)==0)
|
||||
break;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
/** find closest NS or DNAME and returns the rrset (locked) */
|
||||
static struct ub_packed_rrset_key*
|
||||
find_closest_of_type(struct module_env* env, uint8_t* qname, size_t qnamelen,
|
||||
@@ -256,12 +234,12 @@ find_closest_of_type(struct module_env* env, uint8_t* qname, size_t qnamelen,
|
||||
/* check for expiry, but we have to let go of the rrset
|
||||
* for the lock ordering */
|
||||
lock_rw_unlock(&rrset->entry.lock);
|
||||
/* the expired_above function always takes off one
|
||||
* label (if qnamelen>0) and returns the final qname
|
||||
* where it searched, so we can continue from there
|
||||
* turning the O N*N search into O N. */
|
||||
if(!rrset_expired_above(env, &qname, &qnamelen,
|
||||
searchtype, qclass, now, expiretop,
|
||||
/* the rrset_cache_expired_above function always takes
|
||||
* off one label (if qnamelen>0) and returns the final
|
||||
* qname where it searched, so we can continue from
|
||||
* there turning the O N*N search into O N. */
|
||||
if(!rrset_cache_expired_above(env->rrset_cache, &qname,
|
||||
&qnamelen, searchtype, qclass, now, expiretop,
|
||||
expiretoplen)) {
|
||||
/* we want to return rrset, but it may be
|
||||
* gone from cache, if so, just loop like
|
||||
@@ -690,6 +668,28 @@ tomsg(struct module_env* env, struct query_info* q, struct reply_info* r,
|
||||
return msg;
|
||||
}
|
||||
|
||||
struct dns_msg*
|
||||
dns_msg_deepcopy_region(struct dns_msg* origin, struct regional* region)
|
||||
{
|
||||
size_t i;
|
||||
struct dns_msg* res = NULL;
|
||||
res = gen_dns_msg(region, &origin->qinfo, origin->rep->rrset_count);
|
||||
if(!res) return NULL;
|
||||
*res->rep = *origin->rep;
|
||||
if(origin->rep->reason_bogus_str) {
|
||||
res->rep->reason_bogus_str = regional_strdup(region,
|
||||
origin->rep->reason_bogus_str);
|
||||
}
|
||||
for(i=0; i<res->rep->rrset_count; i++) {
|
||||
res->rep->rrsets[i] = packed_rrset_copy_region(
|
||||
origin->rep->rrsets[i], region, 0);
|
||||
if(!res->rep->rrsets[i]) {
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
return res;
|
||||
}
|
||||
|
||||
/** synthesize RRset-only response from cached RRset item */
|
||||
static struct dns_msg*
|
||||
rrset_msg(struct ub_packed_rrset_key* rrset, struct regional* region,
|
||||
@@ -796,7 +796,7 @@ synth_dname_msg(struct ub_packed_rrset_key* rrset, struct regional* region,
|
||||
if(!newd)
|
||||
return NULL;
|
||||
ck->entry.data = newd;
|
||||
newd->ttl = 0; /* 0 for synthesized CNAME TTL */
|
||||
newd->ttl = d->ttl - now; /* RFC6672: synth CNAME TTL == DNAME TTL */
|
||||
newd->count = 1;
|
||||
newd->rrsig_count = 0;
|
||||
newd->trust = rrset_trust_ans_noAA;
|
||||
|
||||
Vendored
+9
@@ -164,6 +164,15 @@ struct dns_msg* tomsg(struct module_env* env, struct query_info* q,
|
||||
struct reply_info* r, struct regional* region, time_t now,
|
||||
int allow_expired, struct regional* scratch);
|
||||
|
||||
/**
|
||||
* Deep copy a dns_msg to a region.
|
||||
* @param origin: the dns_msg to copy.
|
||||
* @param region: the region to copy all the data to.
|
||||
* @return the new dns_msg or NULL on malloc error.
|
||||
*/
|
||||
struct dns_msg* dns_msg_deepcopy_region(struct dns_msg* origin,
|
||||
struct regional* region);
|
||||
|
||||
/**
|
||||
* Find cached message
|
||||
* @param env: module environment with the DNS cache.
|
||||
|
||||
Vendored
+186
-11
@@ -60,6 +60,16 @@
|
||||
* can do this number of packets (until those all timeout too) */
|
||||
#define TIMEOUT_COUNT_MAX 3
|
||||
|
||||
/** Minus 1000 because that is outside of the RTTBAND, so
|
||||
* blacklisted servers stay blacklisted if this is chosen.
|
||||
* If USEFUL_SERVER_TOP_TIMEOUT is below 1000 (configured via RTT_MAX_TIMEOUT,
|
||||
* infra-cache-max-rtt) change it to just above the RTT_BAND. */
|
||||
#define STILL_USEFUL_TIMEOUT ( \
|
||||
USEFUL_SERVER_TOP_TIMEOUT < 1000 || \
|
||||
USEFUL_SERVER_TOP_TIMEOUT - 1000 <= RTT_BAND \
|
||||
?RTT_BAND + 1 \
|
||||
:USEFUL_SERVER_TOP_TIMEOUT - 1000)
|
||||
|
||||
/** ratelimit value for delegation point */
|
||||
int infra_dp_ratelimit = 0;
|
||||
|
||||
@@ -234,6 +244,81 @@ setup_domain_limits(struct infra_cache* infra, struct config_file* cfg)
|
||||
return 1;
|
||||
}
|
||||
|
||||
/** find or create element in wait limit netblock tree */
|
||||
static struct wait_limit_netblock_info*
|
||||
wait_limit_netblock_findcreate(struct infra_cache* infra, char* str,
|
||||
int cookie)
|
||||
{
|
||||
rbtree_type* tree;
|
||||
struct sockaddr_storage addr;
|
||||
int net;
|
||||
socklen_t addrlen;
|
||||
struct wait_limit_netblock_info* d;
|
||||
|
||||
if(!netblockstrtoaddr(str, 0, &addr, &addrlen, &net)) {
|
||||
log_err("cannot parse wait limit netblock '%s'", str);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* can we find it? */
|
||||
if(cookie)
|
||||
tree = &infra->wait_limits_cookie_netblock;
|
||||
else
|
||||
tree = &infra->wait_limits_netblock;
|
||||
d = (struct wait_limit_netblock_info*)addr_tree_find(tree, &addr,
|
||||
addrlen, net);
|
||||
if(d)
|
||||
return d;
|
||||
|
||||
/* create it */
|
||||
d = (struct wait_limit_netblock_info*)calloc(1, sizeof(*d));
|
||||
if(!d)
|
||||
return NULL;
|
||||
d->limit = -1;
|
||||
if(!addr_tree_insert(tree, &d->node, &addr, addrlen, net)) {
|
||||
log_err("duplicate element in domainlimit tree");
|
||||
free(d);
|
||||
return NULL;
|
||||
}
|
||||
return d;
|
||||
}
|
||||
|
||||
|
||||
/** insert wait limit information into lookup tree */
|
||||
static int
|
||||
infra_wait_limit_netblock_insert(struct infra_cache* infra,
|
||||
struct config_file* cfg)
|
||||
{
|
||||
struct config_str2list* p;
|
||||
struct wait_limit_netblock_info* d;
|
||||
for(p = cfg->wait_limit_netblock; p; p = p->next) {
|
||||
d = wait_limit_netblock_findcreate(infra, p->str, 0);
|
||||
if(!d)
|
||||
return 0;
|
||||
d->limit = atoi(p->str2);
|
||||
}
|
||||
for(p = cfg->wait_limit_cookie_netblock; p; p = p->next) {
|
||||
d = wait_limit_netblock_findcreate(infra, p->str, 1);
|
||||
if(!d)
|
||||
return 0;
|
||||
d->limit = atoi(p->str2);
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
/** setup wait limits tree (0 on failure) */
|
||||
static int
|
||||
setup_wait_limits(struct infra_cache* infra, struct config_file* cfg)
|
||||
{
|
||||
addr_tree_init(&infra->wait_limits_netblock);
|
||||
addr_tree_init(&infra->wait_limits_cookie_netblock);
|
||||
if(!infra_wait_limit_netblock_insert(infra, cfg))
|
||||
return 0;
|
||||
addr_tree_init_parents(&infra->wait_limits_netblock);
|
||||
addr_tree_init_parents(&infra->wait_limits_cookie_netblock);
|
||||
return 1;
|
||||
}
|
||||
|
||||
struct infra_cache*
|
||||
infra_create(struct config_file* cfg)
|
||||
{
|
||||
@@ -267,7 +352,12 @@ infra_create(struct config_file* cfg)
|
||||
infra_delete(infra);
|
||||
return NULL;
|
||||
}
|
||||
if(!setup_wait_limits(infra, cfg)) {
|
||||
infra_delete(infra);
|
||||
return NULL;
|
||||
}
|
||||
infra_ip_ratelimit = cfg->ip_ratelimit;
|
||||
infra_ip_ratelimit_cookie = cfg->ip_ratelimit_cookie;
|
||||
infra->client_ip_rates = slabhash_create(cfg->ip_ratelimit_slabs,
|
||||
INFRA_HOST_STARTSIZE, cfg->ip_ratelimit_size, &ip_rate_sizefunc,
|
||||
&ip_rate_compfunc, &ip_rate_delkeyfunc, &ip_rate_deldatafunc, NULL);
|
||||
@@ -287,6 +377,12 @@ static void domain_limit_free(rbnode_type* n, void* ATTR_UNUSED(arg))
|
||||
}
|
||||
}
|
||||
|
||||
/** delete wait_limit_netblock_info entries */
|
||||
static void wait_limit_netblock_del(rbnode_type* n, void* ATTR_UNUSED(arg))
|
||||
{
|
||||
free(n);
|
||||
}
|
||||
|
||||
void
|
||||
infra_delete(struct infra_cache* infra)
|
||||
{
|
||||
@@ -296,6 +392,10 @@ infra_delete(struct infra_cache* infra)
|
||||
slabhash_delete(infra->domain_rates);
|
||||
traverse_postorder(&infra->domain_limits, domain_limit_free, NULL);
|
||||
slabhash_delete(infra->client_ip_rates);
|
||||
traverse_postorder(&infra->wait_limits_netblock,
|
||||
wait_limit_netblock_del, NULL);
|
||||
traverse_postorder(&infra->wait_limits_cookie_netblock,
|
||||
wait_limit_netblock_del, NULL);
|
||||
free(infra);
|
||||
}
|
||||
|
||||
@@ -309,6 +409,7 @@ infra_adjust(struct infra_cache* infra, struct config_file* cfg)
|
||||
infra->infra_keep_probing = cfg->infra_keep_probing;
|
||||
infra_dp_ratelimit = cfg->ratelimit;
|
||||
infra_ip_ratelimit = cfg->ip_ratelimit;
|
||||
infra_ip_ratelimit_cookie = cfg->ip_ratelimit_cookie;
|
||||
maxmem = cfg->infra_cache_numhosts * (sizeof(struct infra_key)+
|
||||
sizeof(struct infra_data)+INFRA_BYTES_NAME);
|
||||
/* divide cachesize by slabs and multiply by slabs, because if the
|
||||
@@ -567,7 +668,7 @@ infra_update_tcp_works(struct infra_cache* infra,
|
||||
if(data->rtt.rto >= RTT_MAX_TIMEOUT)
|
||||
/* do not disqualify this server altogether, it is better
|
||||
* than nothing */
|
||||
data->rtt.rto = RTT_MAX_TIMEOUT-1000;
|
||||
data->rtt.rto = STILL_USEFUL_TIMEOUT;
|
||||
lock_rw_unlock(&e->lock);
|
||||
}
|
||||
|
||||
@@ -707,7 +808,7 @@ infra_get_lame_rtt(struct infra_cache* infra,
|
||||
&& infra->infra_keep_probing) {
|
||||
/* single probe, keep probing */
|
||||
if(*rtt >= USEFUL_SERVER_TOP_TIMEOUT)
|
||||
*rtt = USEFUL_SERVER_TOP_TIMEOUT-1000;
|
||||
*rtt = STILL_USEFUL_TIMEOUT;
|
||||
} else if(host->rtt.rto >= PROBE_MAXRTO && timenow < host->probedelay
|
||||
&& rtt_notimeout(&host->rtt)*4 <= host->rtt.rto) {
|
||||
/* single probe for this domain, and we are not probing */
|
||||
@@ -715,26 +816,23 @@ infra_get_lame_rtt(struct infra_cache* infra,
|
||||
if(qtype == LDNS_RR_TYPE_A) {
|
||||
if(host->timeout_A >= TIMEOUT_COUNT_MAX)
|
||||
*rtt = USEFUL_SERVER_TOP_TIMEOUT;
|
||||
else *rtt = USEFUL_SERVER_TOP_TIMEOUT-1000;
|
||||
else *rtt = STILL_USEFUL_TIMEOUT;
|
||||
} else if(qtype == LDNS_RR_TYPE_AAAA) {
|
||||
if(host->timeout_AAAA >= TIMEOUT_COUNT_MAX)
|
||||
*rtt = USEFUL_SERVER_TOP_TIMEOUT;
|
||||
else *rtt = USEFUL_SERVER_TOP_TIMEOUT-1000;
|
||||
else *rtt = STILL_USEFUL_TIMEOUT;
|
||||
} else {
|
||||
if(host->timeout_other >= TIMEOUT_COUNT_MAX)
|
||||
*rtt = USEFUL_SERVER_TOP_TIMEOUT;
|
||||
else *rtt = USEFUL_SERVER_TOP_TIMEOUT-1000;
|
||||
else *rtt = STILL_USEFUL_TIMEOUT;
|
||||
}
|
||||
}
|
||||
/* expired entry */
|
||||
if(timenow > host->ttl) {
|
||||
|
||||
/* see if this can be a re-probe of an unresponsive server */
|
||||
/* minus 1000 because that is outside of the RTTBAND, so
|
||||
* blacklisted servers stay blacklisted if this is chosen */
|
||||
if(host->rtt.rto >= USEFUL_SERVER_TOP_TIMEOUT) {
|
||||
lock_rw_unlock(&e->lock);
|
||||
*rtt = USEFUL_SERVER_TOP_TIMEOUT-1000;
|
||||
*rtt = STILL_USEFUL_TIMEOUT;
|
||||
*lame = 0;
|
||||
*dnsseclame = 0;
|
||||
*reclame = 0;
|
||||
@@ -880,7 +978,8 @@ static void infra_create_ratedata(struct infra_cache* infra,
|
||||
|
||||
/** create rate data item for ip address */
|
||||
static void infra_ip_create_ratedata(struct infra_cache* infra,
|
||||
struct sockaddr_storage* addr, socklen_t addrlen, time_t timenow)
|
||||
struct sockaddr_storage* addr, socklen_t addrlen, time_t timenow,
|
||||
int mesh_wait)
|
||||
{
|
||||
hashvalue_type h = hash_addr(addr, addrlen, 0);
|
||||
struct ip_rate_key* k = (struct ip_rate_key*)calloc(1, sizeof(*k));
|
||||
@@ -898,6 +997,7 @@ static void infra_ip_create_ratedata(struct infra_cache* infra,
|
||||
k->entry.data = d;
|
||||
d->qps[0] = 1;
|
||||
d->timestamp[0] = timenow;
|
||||
d->mesh_wait = mesh_wait;
|
||||
slabhash_insert(infra->client_ip_rates, h, &k->entry, d, NULL);
|
||||
}
|
||||
|
||||
@@ -1121,6 +1221,81 @@ int infra_ip_ratelimit_inc(struct infra_cache* infra,
|
||||
}
|
||||
|
||||
/* create */
|
||||
infra_ip_create_ratedata(infra, addr, addrlen, timenow);
|
||||
infra_ip_create_ratedata(infra, addr, addrlen, timenow, 0);
|
||||
return 1;
|
||||
}
|
||||
|
||||
int infra_wait_limit_allowed(struct infra_cache* infra, struct comm_reply* rep,
|
||||
int cookie_valid, struct config_file* cfg)
|
||||
{
|
||||
struct lruhash_entry* entry;
|
||||
if(cfg->wait_limit == 0)
|
||||
return 1;
|
||||
|
||||
entry = infra_find_ip_ratedata(infra, &rep->client_addr,
|
||||
rep->client_addrlen, 0);
|
||||
if(entry) {
|
||||
rbtree_type* tree;
|
||||
struct wait_limit_netblock_info* w;
|
||||
struct rate_data* d = (struct rate_data*)entry->data;
|
||||
int mesh_wait = d->mesh_wait;
|
||||
lock_rw_unlock(&entry->lock);
|
||||
|
||||
/* have the wait amount, check how much is allowed */
|
||||
if(cookie_valid)
|
||||
tree = &infra->wait_limits_cookie_netblock;
|
||||
else tree = &infra->wait_limits_netblock;
|
||||
w = (struct wait_limit_netblock_info*)addr_tree_lookup(tree,
|
||||
&rep->client_addr, rep->client_addrlen);
|
||||
if(w) {
|
||||
if(w->limit != -1 && mesh_wait > w->limit)
|
||||
return 0;
|
||||
} else {
|
||||
/* if there is no IP netblock specific information,
|
||||
* use the configured value. */
|
||||
if(mesh_wait > (cookie_valid?cfg->wait_limit_cookie:
|
||||
cfg->wait_limit))
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
void infra_wait_limit_inc(struct infra_cache* infra, struct comm_reply* rep,
|
||||
time_t timenow, struct config_file* cfg)
|
||||
{
|
||||
struct lruhash_entry* entry;
|
||||
if(cfg->wait_limit == 0)
|
||||
return;
|
||||
|
||||
/* Find it */
|
||||
entry = infra_find_ip_ratedata(infra, &rep->client_addr,
|
||||
rep->client_addrlen, 1);
|
||||
if(entry) {
|
||||
struct rate_data* d = (struct rate_data*)entry->data;
|
||||
d->mesh_wait++;
|
||||
lock_rw_unlock(&entry->lock);
|
||||
return;
|
||||
}
|
||||
|
||||
/* Create it */
|
||||
infra_ip_create_ratedata(infra, &rep->client_addr,
|
||||
rep->client_addrlen, timenow, 1);
|
||||
}
|
||||
|
||||
void infra_wait_limit_dec(struct infra_cache* infra, struct comm_reply* rep,
|
||||
struct config_file* cfg)
|
||||
{
|
||||
struct lruhash_entry* entry;
|
||||
if(cfg->wait_limit == 0)
|
||||
return;
|
||||
|
||||
entry = infra_find_ip_ratedata(infra, &rep->client_addr,
|
||||
rep->client_addrlen, 1);
|
||||
if(entry) {
|
||||
struct rate_data* d = (struct rate_data*)entry->data;
|
||||
if(d->mesh_wait > 0)
|
||||
d->mesh_wait--;
|
||||
lock_rw_unlock(&entry->lock);
|
||||
}
|
||||
}
|
||||
|
||||
Vendored
+29
-1
@@ -122,6 +122,10 @@ struct infra_cache {
|
||||
rbtree_type domain_limits;
|
||||
/** hash table with query rates per client ip: ip_rate_key, ip_rate_data */
|
||||
struct slabhash* client_ip_rates;
|
||||
/** tree of addr_tree_node, with wait_limit_netblock_info information */
|
||||
rbtree_type wait_limits_netblock;
|
||||
/** tree of addr_tree_node, with wait_limit_netblock_info information */
|
||||
rbtree_type wait_limits_cookie_netblock;
|
||||
};
|
||||
|
||||
/** ratelimit, unless overridden by domain_limits, 0 is off */
|
||||
@@ -184,10 +188,22 @@ struct rate_data {
|
||||
/** what the timestamp is of the qps array members, counter is
|
||||
* valid for that timestamp. Usually now and now-1. */
|
||||
time_t timestamp[RATE_WINDOW];
|
||||
/** the number of queries waiting in the mesh */
|
||||
int mesh_wait;
|
||||
};
|
||||
|
||||
#define ip_rate_data rate_data
|
||||
|
||||
/**
|
||||
* Data to store the configuration per netblock for the wait limit
|
||||
*/
|
||||
struct wait_limit_netblock_info {
|
||||
/** The addr tree node, this must be first. */
|
||||
struct addr_tree_node node;
|
||||
/** the limit on the amount */
|
||||
int limit;
|
||||
};
|
||||
|
||||
/** infra host cache default hash lookup size */
|
||||
#define INFRA_HOST_STARTSIZE 32
|
||||
/** bytes per zonename reserved in the hostcache, dnamelen(zonename.com.) */
|
||||
@@ -218,7 +234,7 @@ struct infra_cache* infra_adjust(struct infra_cache* infra,
|
||||
struct config_file* cfg);
|
||||
|
||||
/**
|
||||
* Plain find infra data function (used by the the other functions)
|
||||
* Plain find infra data function (used by the other functions)
|
||||
* @param infra: infrastructure cache.
|
||||
* @param addr: host address.
|
||||
* @param addrlen: length of addr.
|
||||
@@ -474,4 +490,16 @@ void ip_rate_delkeyfunc(void* d, void* arg);
|
||||
/* delete data */
|
||||
#define ip_rate_deldatafunc rate_deldatafunc
|
||||
|
||||
/** See if the IP address can have another reply in the wait limit */
|
||||
int infra_wait_limit_allowed(struct infra_cache* infra, struct comm_reply* rep,
|
||||
int cookie_valid, struct config_file* cfg);
|
||||
|
||||
/** Increment number of waiting replies for IP */
|
||||
void infra_wait_limit_inc(struct infra_cache* infra, struct comm_reply* rep,
|
||||
time_t timenow, struct config_file* cfg);
|
||||
|
||||
/** Decrement number of waiting replies for IP */
|
||||
void infra_wait_limit_dec(struct infra_cache* infra, struct comm_reply* rep,
|
||||
struct config_file* cfg);
|
||||
|
||||
#endif /* SERVICES_CACHE_INFRA_H */
|
||||
|
||||
Vendored
+87
@@ -46,6 +46,7 @@
|
||||
#include "util/data/packed_rrset.h"
|
||||
#include "util/data/msgreply.h"
|
||||
#include "util/data/msgparse.h"
|
||||
#include "util/data/dname.h"
|
||||
#include "util/regional.h"
|
||||
#include "util/alloc.h"
|
||||
#include "util/net_help.h"
|
||||
@@ -127,6 +128,9 @@ need_to_update_rrset(void* nd, void* cd, time_t timenow, int equal, int ns)
|
||||
{
|
||||
struct packed_rrset_data* newd = (struct packed_rrset_data*)nd;
|
||||
struct packed_rrset_data* cached = (struct packed_rrset_data*)cd;
|
||||
/* o if new data is expired, current data is better */
|
||||
if( newd->ttl < timenow && cached->ttl >= timenow)
|
||||
return 0;
|
||||
/* o store if rrset has been validated
|
||||
* everything better than bogus data
|
||||
* secure is preferred */
|
||||
@@ -440,6 +444,89 @@ rrset_check_sec_status(struct rrset_cache* r,
|
||||
lock_rw_unlock(&e->lock);
|
||||
}
|
||||
|
||||
void
|
||||
rrset_cache_remove_above(struct rrset_cache* r, uint8_t** qname, size_t*
|
||||
qnamelen, uint16_t searchtype, uint16_t qclass, time_t now, uint8_t*
|
||||
qnametop, size_t qnametoplen)
|
||||
{
|
||||
struct ub_packed_rrset_key *rrset;
|
||||
uint8_t lablen;
|
||||
|
||||
while(*qnamelen > 0) {
|
||||
/* look one label higher */
|
||||
lablen = **qname;
|
||||
*qname += lablen + 1;
|
||||
*qnamelen -= lablen + 1;
|
||||
if(*qnamelen <= 0)
|
||||
return;
|
||||
|
||||
/* stop at qnametop */
|
||||
if(qnametop && *qnamelen == qnametoplen &&
|
||||
query_dname_compare(*qname, qnametop)==0)
|
||||
return;
|
||||
|
||||
if(verbosity >= VERB_ALGO) {
|
||||
/* looks up with a time of 0, to see expired entries */
|
||||
if((rrset = rrset_cache_lookup(r, *qname,
|
||||
*qnamelen, searchtype, qclass, 0, 0, 0))) {
|
||||
struct packed_rrset_data* data =
|
||||
(struct packed_rrset_data*)rrset->entry.data;
|
||||
int expired = (now > data->ttl);
|
||||
lock_rw_unlock(&rrset->entry.lock);
|
||||
if(expired)
|
||||
log_nametypeclass(verbosity, "this "
|
||||
"(grand)parent rrset will be "
|
||||
"removed (expired)",
|
||||
*qname, searchtype, qclass);
|
||||
else log_nametypeclass(verbosity, "this "
|
||||
"(grand)parent rrset will be "
|
||||
"removed",
|
||||
*qname, searchtype, qclass);
|
||||
}
|
||||
}
|
||||
rrset_cache_remove(r, *qname, *qnamelen, searchtype, qclass, 0);
|
||||
}
|
||||
}
|
||||
|
||||
int
|
||||
rrset_cache_expired_above(struct rrset_cache* r, uint8_t** qname, size_t*
|
||||
qnamelen, uint16_t searchtype, uint16_t qclass, time_t now, uint8_t*
|
||||
qnametop, size_t qnametoplen)
|
||||
{
|
||||
struct ub_packed_rrset_key *rrset;
|
||||
uint8_t lablen;
|
||||
|
||||
while(*qnamelen > 0) {
|
||||
/* look one label higher */
|
||||
lablen = **qname;
|
||||
*qname += lablen + 1;
|
||||
*qnamelen -= lablen + 1;
|
||||
if(*qnamelen <= 0)
|
||||
break;
|
||||
|
||||
/* looks up with a time of 0, to see expired entries */
|
||||
if((rrset = rrset_cache_lookup(r, *qname,
|
||||
*qnamelen, searchtype, qclass, 0, 0, 0))) {
|
||||
struct packed_rrset_data* data =
|
||||
(struct packed_rrset_data*)rrset->entry.data;
|
||||
if(now > data->ttl) {
|
||||
/* it is expired, this is not wanted */
|
||||
lock_rw_unlock(&rrset->entry.lock);
|
||||
log_nametypeclass(VERB_ALGO, "this rrset is expired", *qname, searchtype, qclass);
|
||||
return 1;
|
||||
}
|
||||
/* it is not expired, continue looking */
|
||||
lock_rw_unlock(&rrset->entry.lock);
|
||||
}
|
||||
|
||||
/* do not look above the qnametop. */
|
||||
if(qnametop && *qnamelen == qnametoplen &&
|
||||
query_dname_compare(*qname, qnametop)==0)
|
||||
break;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
void rrset_cache_remove(struct rrset_cache* r, uint8_t* nm, size_t nmlen,
|
||||
uint16_t type, uint16_t dclass, uint32_t flags)
|
||||
{
|
||||
|
||||
Vendored
+31
@@ -231,6 +231,37 @@ void rrset_update_sec_status(struct rrset_cache* r,
|
||||
void rrset_check_sec_status(struct rrset_cache* r,
|
||||
struct ub_packed_rrset_key* rrset, time_t now);
|
||||
|
||||
/**
|
||||
* Removes rrsets above the qname, returns upper qname.
|
||||
* @param r: the rrset cache.
|
||||
* @param qname: the start qname, also used as the output.
|
||||
* @param qnamelen: length of qname, updated when it returns.
|
||||
* @param searchtype: qtype to search for.
|
||||
* @param qclass: qclass to search for.
|
||||
* @param now: current time.
|
||||
* @param qnametop: the top qname to stop removal (it is not removed).
|
||||
* @param qnametoplen: length of qnametop.
|
||||
*/
|
||||
void rrset_cache_remove_above(struct rrset_cache* r, uint8_t** qname,
|
||||
size_t* qnamelen, uint16_t searchtype, uint16_t qclass, time_t now,
|
||||
uint8_t* qnametop, size_t qnametoplen);
|
||||
|
||||
/**
|
||||
* Sees if an rrset is expired above the qname, returns upper qname.
|
||||
* @param r: the rrset cache.
|
||||
* @param qname: the start qname, also used as the output.
|
||||
* @param qnamelen: length of qname, updated when it returns.
|
||||
* @param searchtype: qtype to search for.
|
||||
* @param qclass: qclass to search for.
|
||||
* @param now: current time.
|
||||
* @param qnametop: the top qname, don't look farther than that.
|
||||
* @param qnametoplen: length of qnametop.
|
||||
* @return true if there is an expired rrset above, false otherwise.
|
||||
*/
|
||||
int rrset_cache_expired_above(struct rrset_cache* r, uint8_t** qname,
|
||||
size_t* qnamelen, uint16_t searchtype, uint16_t qclass, time_t now,
|
||||
uint8_t* qnametop, size_t qnametoplen);
|
||||
|
||||
/**
|
||||
* Remove an rrset from the cache, by name and type and flags
|
||||
* @param r: rrset cache
|
||||
|
||||
+38
-21
@@ -140,9 +140,11 @@ void
|
||||
verbose_print_unbound_socket(struct unbound_socket* ub_sock)
|
||||
{
|
||||
if(verbosity >= VERB_ALGO) {
|
||||
char buf[256];
|
||||
log_info("listing of unbound_socket structure:");
|
||||
verbose_print_addr(ub_sock->addr);
|
||||
log_info("s is: %d, fam is: %s, acl: %s", ub_sock->s,
|
||||
addr_to_str((void*)ub_sock->addr, ub_sock->addrlen, buf,
|
||||
sizeof(buf));
|
||||
log_info("%s s is: %d, fam is: %s, acl: %s", buf, ub_sock->s,
|
||||
ub_sock->fam == AF_INET?"AF_INET":"AF_INET6",
|
||||
ub_sock->acl?"yes":"no");
|
||||
}
|
||||
@@ -610,7 +612,9 @@ create_udp_sock(int family, int socktype, struct sockaddr* addr,
|
||||
# elif defined(IP_DONTFRAG) && !defined(__APPLE__)
|
||||
/* the IP_DONTFRAG option if defined in the 11.0 OSX headers,
|
||||
* but does not work on that version, so we exclude it */
|
||||
int off = 0;
|
||||
/* a nonzero value disables fragmentation, according to
|
||||
* docs.oracle.com for ip(4). */
|
||||
int off = 1;
|
||||
if (setsockopt(s, IPPROTO_IP, IP_DONTFRAG,
|
||||
&off, (socklen_t)sizeof(off)) < 0) {
|
||||
log_err("setsockopt(..., IP_DONTFRAG, ...) failed: %s",
|
||||
@@ -1047,7 +1051,22 @@ make_sock(int stype, const char* ifname, const char* port,
|
||||
}
|
||||
}
|
||||
|
||||
ub_sock->addr = res;
|
||||
if(!res->ai_addr) {
|
||||
log_err("getaddrinfo returned no address");
|
||||
freeaddrinfo(res);
|
||||
sock_close(s);
|
||||
return -1;
|
||||
}
|
||||
ub_sock->addr = memdup(res->ai_addr, res->ai_addrlen);
|
||||
ub_sock->addrlen = res->ai_addrlen;
|
||||
if(!ub_sock->addr) {
|
||||
log_err("out of memory: allocate listening address");
|
||||
freeaddrinfo(res);
|
||||
sock_close(s);
|
||||
return -1;
|
||||
}
|
||||
freeaddrinfo(res);
|
||||
|
||||
ub_sock->s = s;
|
||||
ub_sock->fam = hints->ai_family;
|
||||
ub_sock->acl = NULL;
|
||||
@@ -1277,8 +1296,7 @@ ports_create_if(const char* ifname, int do_auto, int do_udp, int do_tcp,
|
||||
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)) == -1) {
|
||||
if(ub_sock->addr)
|
||||
freeaddrinfo(ub_sock->addr);
|
||||
free(ub_sock->addr);
|
||||
free(ub_sock);
|
||||
if(noip6) {
|
||||
log_warn("IPv6 protocol not available");
|
||||
@@ -1289,8 +1307,7 @@ ports_create_if(const char* ifname, int do_auto, int do_udp, int do_tcp,
|
||||
/* getting source addr packet info is highly non-portable */
|
||||
if(!set_recvpktinfo(s, hints->ai_family)) {
|
||||
sock_close(s);
|
||||
if(ub_sock->addr)
|
||||
freeaddrinfo(ub_sock->addr);
|
||||
free(ub_sock->addr);
|
||||
free(ub_sock);
|
||||
return 0;
|
||||
}
|
||||
@@ -1301,8 +1318,7 @@ ports_create_if(const char* ifname, int do_auto, int do_udp, int do_tcp,
|
||||
?listen_type_udpancil_dnscrypt:listen_type_udpancil,
|
||||
is_pp2, ub_sock)) {
|
||||
sock_close(s);
|
||||
if(ub_sock->addr)
|
||||
freeaddrinfo(ub_sock->addr);
|
||||
free(ub_sock->addr);
|
||||
free(ub_sock);
|
||||
return 0;
|
||||
}
|
||||
@@ -1314,8 +1330,7 @@ ports_create_if(const char* ifname, int do_auto, int do_udp, int do_tcp,
|
||||
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)) == -1) {
|
||||
if(ub_sock->addr)
|
||||
freeaddrinfo(ub_sock->addr);
|
||||
free(ub_sock->addr);
|
||||
free(ub_sock);
|
||||
if(noip6) {
|
||||
log_warn("IPv6 protocol not available");
|
||||
@@ -1327,11 +1342,12 @@ ports_create_if(const char* ifname, int do_auto, int do_udp, int do_tcp,
|
||||
log_warn("socket timestamping is not available");
|
||||
}
|
||||
if(!port_insert(list, s, is_dnscrypt
|
||||
?listen_type_udp_dnscrypt:listen_type_udp,
|
||||
?listen_type_udp_dnscrypt :
|
||||
(sock_queue_timeout ?
|
||||
listen_type_udpancil:listen_type_udp),
|
||||
is_pp2, ub_sock)) {
|
||||
sock_close(s);
|
||||
if(ub_sock->addr)
|
||||
freeaddrinfo(ub_sock->addr);
|
||||
free(ub_sock->addr);
|
||||
free(ub_sock);
|
||||
return 0;
|
||||
}
|
||||
@@ -1354,8 +1370,7 @@ ports_create_if(const char* ifname, int do_auto, int do_udp, int do_tcp,
|
||||
if((s = make_sock_port(SOCK_STREAM, ifname, port, hints, 1,
|
||||
&noip6, 0, 0, reuseport, transparent, tcp_mss, nodelay,
|
||||
freebind, use_systemd, dscp, ub_sock)) == -1) {
|
||||
if(ub_sock->addr)
|
||||
freeaddrinfo(ub_sock->addr);
|
||||
free(ub_sock->addr);
|
||||
free(ub_sock);
|
||||
if(noip6) {
|
||||
/*log_warn("IPv6 protocol not available");*/
|
||||
@@ -1367,8 +1382,7 @@ ports_create_if(const char* ifname, int do_auto, int do_udp, int do_tcp,
|
||||
verbose(VERB_ALGO, "setup TCP for SSL service");
|
||||
if(!port_insert(list, s, port_type, is_pp2, ub_sock)) {
|
||||
sock_close(s);
|
||||
if(ub_sock->addr)
|
||||
freeaddrinfo(ub_sock->addr);
|
||||
free(ub_sock->addr);
|
||||
free(ub_sock);
|
||||
return 0;
|
||||
}
|
||||
@@ -1498,9 +1512,13 @@ listen_create(struct comm_base* base, struct listen_port* ports,
|
||||
}
|
||||
} else if(ports->ftype == listen_type_udpancil ||
|
||||
ports->ftype == listen_type_udpancil_dnscrypt) {
|
||||
#if defined(AF_INET6) && defined(IPV6_PKTINFO) && defined(HAVE_RECVMSG)
|
||||
cp = comm_point_create_udp_ancil(base, ports->fd,
|
||||
front->udp_buff, ports->pp2_enabled, cb,
|
||||
cb_arg, ports->socket);
|
||||
#else
|
||||
log_warn("This system does not support UDP ancilliary data.");
|
||||
#endif
|
||||
}
|
||||
if(!cp) {
|
||||
log_err("can't create commpoint");
|
||||
@@ -1946,8 +1964,7 @@ void listening_ports_free(struct listen_port* list)
|
||||
}
|
||||
/* rc_ports don't have ub_socket */
|
||||
if(list->socket) {
|
||||
if(list->socket->addr)
|
||||
freeaddrinfo(list->socket->addr);
|
||||
free(list->socket->addr);
|
||||
free(list->socket);
|
||||
}
|
||||
free(list);
|
||||
|
||||
@@ -107,11 +107,13 @@ enum listen_type {
|
||||
* socket properties (just like NSD nsd_socket structure definition)
|
||||
*/
|
||||
struct unbound_socket {
|
||||
/** socket-address structure */
|
||||
struct addrinfo* addr;
|
||||
/** the address of the socket */
|
||||
struct sockaddr* addr;
|
||||
/** length of the address */
|
||||
socklen_t addrlen;
|
||||
/** socket descriptor returned by socket() syscall */
|
||||
int s;
|
||||
/** address family (AF_INET/IF_INET6) */
|
||||
/** address family (AF_INET/AF_INET6) */
|
||||
int fam;
|
||||
/** ACL on the socket (listening interface) */
|
||||
struct acl_addr* acl;
|
||||
|
||||
+49
-38
@@ -242,7 +242,7 @@ lz_enter_zone_dname(struct local_zones* zones, uint8_t* nm, size_t len,
|
||||
}
|
||||
|
||||
/** enter a new zone */
|
||||
static struct local_zone*
|
||||
struct local_zone*
|
||||
lz_enter_zone(struct local_zones* zones, const char* name, const char* type,
|
||||
uint16_t dclass)
|
||||
{
|
||||
@@ -330,14 +330,16 @@ get_rr_nameclass(const char* str, uint8_t** nm, uint16_t* dclass,
|
||||
static struct local_rrset*
|
||||
local_data_find_type(struct local_data* data, uint16_t type, int alias_ok)
|
||||
{
|
||||
struct local_rrset* p;
|
||||
struct local_rrset* p, *cname = NULL;
|
||||
type = htons(type);
|
||||
for(p = data->rrsets; p; p = p->next) {
|
||||
if(p->rrset->rk.type == type)
|
||||
return p;
|
||||
if(alias_ok && p->rrset->rk.type == htons(LDNS_RR_TYPE_CNAME))
|
||||
return p;
|
||||
cname = p;
|
||||
}
|
||||
if(alias_ok)
|
||||
return cname;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
@@ -981,40 +983,43 @@ lz_enter_overrides(struct local_zones* zones, struct config_file* cfg)
|
||||
return 1;
|
||||
}
|
||||
|
||||
/** setup parent pointers, so that a lookup can be done for closest match */
|
||||
static void
|
||||
init_parents(struct local_zones* zones)
|
||||
/* return closest parent in the tree, NULL if none */
|
||||
static struct local_zone* find_closest_parent(struct local_zone* curr,
|
||||
struct local_zone* prev)
|
||||
{
|
||||
struct local_zone* node, *prev = NULL, *p;
|
||||
int m;
|
||||
lock_rw_wrlock(&zones->lock);
|
||||
RBTREE_FOR(node, struct local_zone*, &zones->ztree) {
|
||||
lock_rw_wrlock(&node->lock);
|
||||
node->parent = NULL;
|
||||
if(!prev || prev->dclass != node->dclass) {
|
||||
prev = node;
|
||||
lock_rw_unlock(&node->lock);
|
||||
continue;
|
||||
}
|
||||
(void)dname_lab_cmp(prev->name, prev->namelabs, node->name,
|
||||
node->namelabs, &m); /* we know prev is smaller */
|
||||
/* sort order like: . com. bla.com. zwb.com. net. */
|
||||
/* find the previous, or parent-parent-parent */
|
||||
for(p = prev; p; p = p->parent)
|
||||
/* looking for name with few labels, a parent */
|
||||
if(p->namelabs <= m) {
|
||||
/* ==: since prev matched m, this is closest*/
|
||||
/* <: prev matches more, but is not a parent,
|
||||
* this one is a (grand)parent */
|
||||
node->parent = p;
|
||||
break;
|
||||
}
|
||||
prev = node;
|
||||
struct local_zone* p;
|
||||
int m;
|
||||
if(!prev || prev->dclass != curr->dclass) return NULL;
|
||||
(void)dname_lab_cmp(prev->name, prev->namelabs, curr->name,
|
||||
curr->namelabs, &m); /* we know prev is smaller */
|
||||
/* sort order like: . com. bla.com. zwb.com. net. */
|
||||
/* find the previous, or parent-parent-parent */
|
||||
for(p = prev; p; p = p->parent) {
|
||||
/* looking for name with few labels, a parent */
|
||||
if(p->namelabs <= m) {
|
||||
/* ==: since prev matched m, this is closest*/
|
||||
/* <: prev matches more, but is not a parent,
|
||||
* this one is a (grand)parent */
|
||||
return p;
|
||||
}
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/** setup parent pointers, so that a lookup can be done for closest match */
|
||||
void
|
||||
lz_init_parents(struct local_zones* zones)
|
||||
{
|
||||
struct local_zone* node, *prev = NULL;
|
||||
lock_rw_wrlock(&zones->lock);
|
||||
RBTREE_FOR(node, struct local_zone*, &zones->ztree) {
|
||||
lock_rw_wrlock(&node->lock);
|
||||
node->parent = find_closest_parent(node, prev);
|
||||
prev = node;
|
||||
if(node->override_tree)
|
||||
addr_tree_init_parents(node->override_tree);
|
||||
lock_rw_unlock(&node->lock);
|
||||
}
|
||||
}
|
||||
lock_rw_unlock(&zones->lock);
|
||||
}
|
||||
|
||||
@@ -1034,7 +1039,7 @@ lz_setup_implicit(struct local_zones* zones, struct config_file* cfg)
|
||||
int nmlabs = 0;
|
||||
int match = 0; /* number of labels match count */
|
||||
|
||||
init_parents(zones); /* to enable local_zones_lookup() */
|
||||
lz_init_parents(zones); /* to enable local_zones_lookup() */
|
||||
for(p = cfg->local_data; p; p = p->next) {
|
||||
uint8_t* rr_name;
|
||||
uint16_t rr_class, rr_type;
|
||||
@@ -1200,7 +1205,7 @@ local_zones_apply_cfg(struct local_zones* zones, struct config_file* cfg)
|
||||
}
|
||||
|
||||
/* setup parent ptrs for lookup during data entry */
|
||||
init_parents(zones);
|
||||
lz_init_parents(zones);
|
||||
/* insert local zone tags */
|
||||
if(!lz_enter_zone_tags(zones, cfg)) {
|
||||
return 0;
|
||||
@@ -1532,7 +1537,7 @@ local_data_answer(struct local_zone* z, struct module_env* env,
|
||||
return 0; /* invalid cname */
|
||||
if(dname_is_wild(ctarget)) {
|
||||
/* synthesize cname target */
|
||||
struct packed_rrset_data* d;
|
||||
struct packed_rrset_data* d, *lr_d;
|
||||
/* -3 for wildcard label and root label from qname */
|
||||
size_t newtargetlen = qinfo->qname_len + ctargetlen - 3;
|
||||
|
||||
@@ -1560,8 +1565,10 @@ local_data_answer(struct local_zone* z, struct module_env* env,
|
||||
+ newtargetlen);
|
||||
if(!d)
|
||||
return 0; /* out of memory */
|
||||
lr_d = (struct packed_rrset_data*)lr->rrset->entry.data;
|
||||
qinfo->local_alias->rrset->entry.data = d;
|
||||
d->ttl = 0; /* 0 for synthesized CNAME TTL */
|
||||
d->ttl = lr_d->rr_ttl[0]; /* RFC6672-like behavior:
|
||||
synth CNAME TTL uses original TTL*/
|
||||
d->count = 1;
|
||||
d->rrsig_count = 0;
|
||||
d->trust = rrset_trust_ans_noAA;
|
||||
@@ -2024,7 +2031,9 @@ struct local_zone* local_zones_add_zone(struct local_zones* zones,
|
||||
uint8_t* name, size_t len, int labs, uint16_t dclass,
|
||||
enum localzone_type tp)
|
||||
{
|
||||
int exact;
|
||||
/* create */
|
||||
struct local_zone *prev;
|
||||
struct local_zone* z = local_zone_create(name, len, labs, tp, dclass);
|
||||
if(!z) {
|
||||
free(name);
|
||||
@@ -2033,10 +2042,12 @@ struct local_zone* local_zones_add_zone(struct local_zones* zones,
|
||||
lock_rw_wrlock(&z->lock);
|
||||
|
||||
/* find the closest parent */
|
||||
z->parent = local_zones_find(zones, name, len, labs, dclass);
|
||||
prev = local_zones_find_le(zones, name, len, labs, dclass, &exact);
|
||||
if(!exact)
|
||||
z->parent = find_closest_parent(z, prev);
|
||||
|
||||
/* insert into the tree */
|
||||
if(!rbtree_insert(&zones->ztree, &z->node)) {
|
||||
if(exact||!rbtree_insert(&zones->ztree, &z->node)) {
|
||||
/* duplicate entry! */
|
||||
lock_rw_unlock(&z->lock);
|
||||
local_zone_delete(z);
|
||||
|
||||
@@ -641,4 +641,23 @@ local_zone_enter_rr(struct local_zone* z, uint8_t* nm, size_t nmlen,
|
||||
*/
|
||||
struct local_data*
|
||||
local_zone_find_data(struct local_zone* z, uint8_t* nm, size_t nmlen, int nmlabs);
|
||||
|
||||
/** Enter a new zone; returns with WRlock
|
||||
* Made public for unit testing
|
||||
* @param zones: the local zones tree
|
||||
* @param name: name of the zone
|
||||
* @param type: type of the zone
|
||||
* @param dclass: class of the zone
|
||||
* @return local_zone (or duplicate), NULL on parse and malloc failures
|
||||
*/
|
||||
struct local_zone*
|
||||
lz_enter_zone(struct local_zones* zones, const char* name, const char* type,
|
||||
uint16_t dclass);
|
||||
|
||||
/** Setup parent pointers, so that a lookup can be done for closest match
|
||||
* Made public for unit testing
|
||||
* @param zones: the local zones tree
|
||||
*/
|
||||
void
|
||||
lz_init_parents(struct local_zones* zones);
|
||||
#endif /* SERVICES_LOCALZONE_H */
|
||||
|
||||
+147
-17
@@ -47,6 +47,7 @@
|
||||
#include "services/outbound_list.h"
|
||||
#include "services/cache/dns.h"
|
||||
#include "services/cache/rrset.h"
|
||||
#include "services/cache/infra.h"
|
||||
#include "util/log.h"
|
||||
#include "util/net_help.h"
|
||||
#include "util/module.h"
|
||||
@@ -69,6 +70,12 @@
|
||||
#include "edns-subnet/subnetmod.h"
|
||||
#include "edns-subnet/edns-subnet.h"
|
||||
#endif
|
||||
#ifdef HAVE_SYS_TYPES_H
|
||||
# include <sys/types.h>
|
||||
#endif
|
||||
#ifdef HAVE_NETDB_H
|
||||
#include <netdb.h>
|
||||
#endif
|
||||
|
||||
/**
|
||||
* Compare two response-ip client info entries for the purpose of mesh state
|
||||
@@ -379,7 +386,7 @@ mesh_serve_expired_init(struct mesh_state* mstate, int timeout)
|
||||
&mesh_serve_expired_lookup;
|
||||
|
||||
/* In case this timer already popped, start it again */
|
||||
if(!mstate->s.serve_expired_data->timer) {
|
||||
if(!mstate->s.serve_expired_data->timer && timeout != -1) {
|
||||
mstate->s.serve_expired_data->timer = comm_timer_create(
|
||||
mstate->s.env->worker_base, mesh_serve_expired_callback, mstate);
|
||||
if(!mstate->s.serve_expired_data->timer)
|
||||
@@ -406,11 +413,20 @@ void mesh_new_client(struct mesh_area* mesh, struct query_info* qinfo,
|
||||
int timeout = mesh->env->cfg->serve_expired?
|
||||
mesh->env->cfg->serve_expired_client_timeout:0;
|
||||
struct sldns_buffer* r_buffer = rep->c->buffer;
|
||||
uint16_t mesh_flags = qflags&(BIT_RD|BIT_CD);
|
||||
if(rep->c->tcp_req_info) {
|
||||
r_buffer = rep->c->tcp_req_info->spool_buffer;
|
||||
}
|
||||
if(!infra_wait_limit_allowed(mesh->env->infra_cache, rep,
|
||||
edns->cookie_valid, mesh->env->cfg)) {
|
||||
verbose(VERB_ALGO, "Too many queries waiting from the IP. "
|
||||
"dropping incoming query.");
|
||||
comm_point_drop_reply(rep);
|
||||
mesh->stats_dropped++;
|
||||
return;
|
||||
}
|
||||
if(!unique)
|
||||
s = mesh_area_find(mesh, cinfo, qinfo, qflags&(BIT_RD|BIT_CD), 0, 0);
|
||||
s = mesh_area_find(mesh, cinfo, qinfo, mesh_flags, 0, 0);
|
||||
/* does this create a new reply state? */
|
||||
if(!s || s->list_select == mesh_no_list) {
|
||||
if(!mesh_make_new_space(mesh, rep->c->buffer)) {
|
||||
@@ -438,7 +454,7 @@ void mesh_new_client(struct mesh_area* mesh, struct query_info* qinfo,
|
||||
struct rbnode_type* n;
|
||||
#endif
|
||||
s = mesh_state_create(mesh->env, qinfo, cinfo,
|
||||
qflags&(BIT_RD|BIT_CD), 0, 0);
|
||||
mesh_flags, 0, 0);
|
||||
if(!s) {
|
||||
log_err("mesh_state_create: out of memory; SERVFAIL");
|
||||
if(!inplace_cb_reply_servfail_call(mesh->env, qinfo, NULL, NULL,
|
||||
@@ -505,6 +521,19 @@ void mesh_new_client(struct mesh_area* mesh, struct query_info* qinfo,
|
||||
log_err("mesh_new_client: out of memory initializing serve expired");
|
||||
goto servfail_mem;
|
||||
}
|
||||
#ifdef USE_CACHEDB
|
||||
if(!timeout && mesh->env->cfg->serve_expired &&
|
||||
!mesh->env->cfg->serve_expired_client_timeout &&
|
||||
(mesh->env->cachedb_enabled &&
|
||||
mesh->env->cfg->cachedb_check_when_serve_expired)) {
|
||||
if(!mesh_serve_expired_init(s, -1)) {
|
||||
log_err("mesh_new_client: out of memory initializing serve expired");
|
||||
goto servfail_mem;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
infra_wait_limit_inc(mesh->env->infra_cache, rep, *mesh->env->now,
|
||||
mesh->env->cfg);
|
||||
/* update statistics */
|
||||
if(was_detached) {
|
||||
log_assert(mesh->num_detached_states > 0);
|
||||
@@ -537,6 +566,8 @@ servfail_mem:
|
||||
edns->opt_list_inplace_cb_out = NULL;
|
||||
error_encode(r_buffer, LDNS_RCODE_SERVFAIL,
|
||||
qinfo, qid, qflags, edns);
|
||||
if(rep->c->use_h2)
|
||||
http2_stream_remove_mesh_state(rep->c->h2_stream);
|
||||
comm_point_send_reply(rep);
|
||||
if(added)
|
||||
mesh_state_delete(&s->s);
|
||||
@@ -555,8 +586,9 @@ mesh_new_callback(struct mesh_area* mesh, struct query_info* qinfo,
|
||||
int was_detached = 0;
|
||||
int was_noreply = 0;
|
||||
int added = 0;
|
||||
uint16_t mesh_flags = qflags&(BIT_RD|BIT_CD);
|
||||
if(!unique)
|
||||
s = mesh_area_find(mesh, NULL, qinfo, qflags&(BIT_RD|BIT_CD), 0, 0);
|
||||
s = mesh_area_find(mesh, NULL, qinfo, mesh_flags, 0, 0);
|
||||
|
||||
/* there are no limits on the number of callbacks */
|
||||
|
||||
@@ -566,7 +598,7 @@ mesh_new_callback(struct mesh_area* mesh, struct query_info* qinfo,
|
||||
struct rbnode_type* n;
|
||||
#endif
|
||||
s = mesh_state_create(mesh->env, qinfo, NULL,
|
||||
qflags&(BIT_RD|BIT_CD), 0, 0);
|
||||
mesh_flags, 0, 0);
|
||||
if(!s) {
|
||||
return 0;
|
||||
}
|
||||
@@ -610,6 +642,18 @@ mesh_new_callback(struct mesh_area* mesh, struct query_info* qinfo,
|
||||
mesh_state_delete(&s->s);
|
||||
return 0;
|
||||
}
|
||||
#ifdef USE_CACHEDB
|
||||
if(!timeout && mesh->env->cfg->serve_expired &&
|
||||
!mesh->env->cfg->serve_expired_client_timeout &&
|
||||
(mesh->env->cachedb_enabled &&
|
||||
mesh->env->cfg->cachedb_check_when_serve_expired)) {
|
||||
if(!mesh_serve_expired_init(s, -1)) {
|
||||
if(added)
|
||||
mesh_state_delete(&s->s);
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
/* update statistics */
|
||||
if(was_detached) {
|
||||
log_assert(mesh->num_detached_states > 0);
|
||||
@@ -633,8 +677,12 @@ static void mesh_schedule_prefetch(struct mesh_area* mesh,
|
||||
struct query_info* qinfo, uint16_t qflags, time_t leeway, int run,
|
||||
int rpz_passthru)
|
||||
{
|
||||
/* Explicitly set the BIT_RD regardless of the client's flags. This is
|
||||
* for a prefetch query (no client attached) but it needs to be treated
|
||||
* as a recursion query. */
|
||||
uint16_t mesh_flags = BIT_RD|(qflags&BIT_CD);
|
||||
struct mesh_state* s = mesh_area_find(mesh, NULL, qinfo,
|
||||
qflags&(BIT_RD|BIT_CD), 0, 0);
|
||||
mesh_flags, 0, 0);
|
||||
#ifdef UNBOUND_DEBUG
|
||||
struct rbnode_type* n;
|
||||
#endif
|
||||
@@ -654,8 +702,7 @@ static void mesh_schedule_prefetch(struct mesh_area* mesh,
|
||||
return;
|
||||
}
|
||||
|
||||
s = mesh_state_create(mesh->env, qinfo, NULL,
|
||||
qflags&(BIT_RD|BIT_CD), 0, 0);
|
||||
s = mesh_state_create(mesh->env, qinfo, NULL, mesh_flags, 0, 0);
|
||||
if(!s) {
|
||||
log_err("prefetch mesh_state_create: out of memory");
|
||||
return;
|
||||
@@ -716,14 +763,17 @@ static void mesh_schedule_prefetch_subnet(struct mesh_area* mesh,
|
||||
#ifdef UNBOUND_DEBUG
|
||||
struct rbnode_type* n;
|
||||
#endif
|
||||
/* Explicitly set the BIT_RD regardless of the client's flags. This is
|
||||
* for a prefetch query (no client attached) but it needs to be treated
|
||||
* as a recursion query. */
|
||||
uint16_t mesh_flags = BIT_RD|(qflags&BIT_CD);
|
||||
if(!mesh_make_new_space(mesh, NULL)) {
|
||||
verbose(VERB_ALGO, "Too many queries. dropped prefetch.");
|
||||
mesh->stats_dropped ++;
|
||||
return;
|
||||
}
|
||||
|
||||
s = mesh_state_create(mesh->env, qinfo, NULL,
|
||||
qflags&(BIT_RD|BIT_CD), 0, 0);
|
||||
s = mesh_state_create(mesh->env, qinfo, NULL, mesh_flags, 0, 0);
|
||||
if(!s) {
|
||||
log_err("prefetch_subnet mesh_state_create: out of memory");
|
||||
return;
|
||||
@@ -924,6 +974,10 @@ mesh_state_cleanup(struct mesh_state* mstate)
|
||||
* takes no time and also it does not do the mesh accounting */
|
||||
mstate->reply_list = NULL;
|
||||
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--;
|
||||
@@ -1173,7 +1227,7 @@ mesh_do_callback(struct mesh_state* m, int rcode, struct reply_info* rep,
|
||||
rcode = LDNS_RCODE_SERVFAIL;
|
||||
if(!rcode && rep && (rep->security == sec_status_bogus ||
|
||||
rep->security == sec_status_secure_sentinel_fail)) {
|
||||
if(!(reason = errinf_to_str_bogus(&m->s)))
|
||||
if(!(reason = errinf_to_str_bogus(&m->s, NULL)))
|
||||
rcode = LDNS_RCODE_SERVFAIL;
|
||||
}
|
||||
/* send the reply */
|
||||
@@ -1197,6 +1251,8 @@ mesh_do_callback(struct mesh_state* m, int rcode, struct reply_info* rep,
|
||||
r->edns.udp_size = EDNS_ADVERTISED_SIZE;
|
||||
r->edns.ext_rcode = 0;
|
||||
r->edns.bits &= EDNS_DO;
|
||||
if(m->s.env->cfg->disable_edns_do && (r->edns.bits&EDNS_DO))
|
||||
r->edns.edns_present = 0;
|
||||
|
||||
if(!inplace_cb_reply_call(m->s.env, &m->s.qinfo, &m->s, rep,
|
||||
LDNS_RCODE_NOERROR, &r->edns, NULL, m->s.region, start_time) ||
|
||||
@@ -1224,11 +1280,12 @@ static inline int
|
||||
mesh_is_rpz_respip_tcponly_action(struct mesh_state const* m)
|
||||
{
|
||||
struct respip_action_info const* respip_info = m->s.respip_action_info;
|
||||
return respip_info == NULL
|
||||
return (respip_info == NULL
|
||||
? 0
|
||||
: (respip_info->rpz_used
|
||||
&& !respip_info->rpz_disabled
|
||||
&& respip_info->action == respip_truncate);
|
||||
&& respip_info->action == respip_truncate))
|
||||
|| m->s.tcp_required;
|
||||
}
|
||||
|
||||
static inline int
|
||||
@@ -1371,6 +1428,8 @@ mesh_send_reply(struct mesh_state* m, int rcode, struct reply_info* rep,
|
||||
r->edns.udp_size = EDNS_ADVERTISED_SIZE;
|
||||
r->edns.ext_rcode = 0;
|
||||
r->edns.bits &= EDNS_DO;
|
||||
if(m->s.env->cfg->disable_edns_do && (r->edns.bits&EDNS_DO))
|
||||
r->edns.edns_present = 0;
|
||||
m->s.qinfo.qname = r->qname;
|
||||
m->s.qinfo.local_alias = r->local_alias;
|
||||
|
||||
@@ -1402,6 +1461,8 @@ mesh_send_reply(struct mesh_state* m, int rcode, struct reply_info* rep,
|
||||
comm_point_send_reply(&r->query_reply);
|
||||
m->reply_list = rlist;
|
||||
}
|
||||
infra_wait_limit_dec(m->s.env->infra_cache, &r->query_reply,
|
||||
m->s.env->cfg);
|
||||
/* account */
|
||||
log_assert(m->s.env->mesh->num_reply_addrs > 0);
|
||||
m->s.env->mesh->num_reply_addrs--;
|
||||
@@ -1424,7 +1485,9 @@ mesh_send_reply(struct mesh_state* m, int rcode, struct reply_info* rep,
|
||||
if(m->s.env->cfg->log_replies) {
|
||||
log_reply_info(NO_VERBOSE, &m->s.qinfo,
|
||||
&r->query_reply.client_addr,
|
||||
r->query_reply.client_addrlen, duration, 0, r_buffer);
|
||||
r->query_reply.client_addrlen, duration, 0, r_buffer,
|
||||
(m->s.env->cfg->log_destaddr?(void*)r->query_reply.c->socket->addr:NULL),
|
||||
r->query_reply.c->type);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1451,12 +1514,34 @@ void mesh_query_done(struct mesh_state* mstate)
|
||||
&& mstate->s.env->cfg->log_servfail
|
||||
&& !mstate->s.env->cfg->val_log_squelch) {
|
||||
char* err = errinf_to_str_servfail(&mstate->s);
|
||||
if(err)
|
||||
log_err("%s", err);
|
||||
free(err);
|
||||
if(err) { log_err("%s", err); }
|
||||
}
|
||||
}
|
||||
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 &&
|
||||
((int)old.tv_sec)*1000+((int)old.tv_usec)/1000 >
|
||||
mstate->s.env->cfg->discard_timeout) {
|
||||
/* Drop the reply, it is too old */
|
||||
/* briefly set the reply_list to NULL, so that the
|
||||
* tcp req info cleanup routine that calls the mesh
|
||||
* to deregister the meshstate for it is not done
|
||||
* because the list is NULL and also accounting is not
|
||||
* done there, but instead we do that here. */
|
||||
struct mesh_reply* reply_list = mstate->reply_list;
|
||||
verbose(VERB_ALGO, "drop reply, it is older than discard-timeout");
|
||||
infra_wait_limit_dec(mstate->s.env->infra_cache,
|
||||
&r->query_reply, mstate->s.env->cfg);
|
||||
mstate->reply_list = NULL;
|
||||
if(r->query_reply.c->use_h2)
|
||||
http2_stream_remove_mesh_state(r->h2_stream);
|
||||
comm_point_drop_reply(&r->query_reply);
|
||||
mstate->reply_list = reply_list;
|
||||
mstate->s.env->mesh->stats_dropped++;
|
||||
continue;
|
||||
}
|
||||
|
||||
i++;
|
||||
tv = r->start_time;
|
||||
|
||||
@@ -1480,7 +1565,12 @@ void mesh_query_done(struct mesh_state* mstate)
|
||||
* because the list is NULL and also accounting is not
|
||||
* done there, but instead we do that here. */
|
||||
struct mesh_reply* reply_list = mstate->reply_list;
|
||||
infra_wait_limit_dec(mstate->s.env->infra_cache,
|
||||
&r->query_reply, mstate->s.env->cfg);
|
||||
mstate->reply_list = NULL;
|
||||
if(r->query_reply.c->use_h2) {
|
||||
http2_stream_remove_mesh_state(r->h2_stream);
|
||||
}
|
||||
comm_point_drop_reply(&r->query_reply);
|
||||
mstate->reply_list = reply_list;
|
||||
} else {
|
||||
@@ -1495,6 +1585,8 @@ void mesh_query_done(struct mesh_state* mstate)
|
||||
tcp_req_info_remove_mesh_state(r->query_reply.c->tcp_req_info, mstate);
|
||||
r_buffer = NULL;
|
||||
}
|
||||
/* mesh_send_reply removed mesh state from
|
||||
* http2_stream. */
|
||||
prev = r;
|
||||
prev_buffer = r_buffer;
|
||||
}
|
||||
@@ -1647,6 +1739,7 @@ int mesh_state_add_reply(struct mesh_state* s, struct edns_data* edns,
|
||||
return 0;
|
||||
if(rep->c->use_h2)
|
||||
r->h2_stream = rep->c->h2_stream;
|
||||
else r->h2_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
|
||||
@@ -2012,6 +2105,8 @@ void mesh_state_remove_reply(struct mesh_area* mesh, struct mesh_state* m,
|
||||
/* delete it, but allocated in m region */
|
||||
log_assert(mesh->num_reply_addrs > 0);
|
||||
mesh->num_reply_addrs--;
|
||||
infra_wait_limit_dec(mesh->env->infra_cache,
|
||||
&n->query_reply, mesh->env->cfg);
|
||||
|
||||
/* prev = prev; */
|
||||
n = n->next;
|
||||
@@ -2152,6 +2247,30 @@ 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 &&
|
||||
((int)old.tv_sec)*1000+((int)old.tv_usec)/1000 >
|
||||
mstate->s.env->cfg->discard_timeout) {
|
||||
/* Drop the reply, it is too old */
|
||||
/* briefly set the reply_list to NULL, so that the
|
||||
* tcp req info cleanup routine that calls the mesh
|
||||
* to deregister the meshstate for it is not done
|
||||
* because the list is NULL and also accounting is not
|
||||
* done there, but instead we do that here. */
|
||||
struct mesh_reply* reply_list = mstate->reply_list;
|
||||
verbose(VERB_ALGO, "drop reply, it is older than discard-timeout");
|
||||
infra_wait_limit_dec(mstate->s.env->infra_cache,
|
||||
&r->query_reply, mstate->s.env->cfg);
|
||||
mstate->reply_list = NULL;
|
||||
if(r->query_reply.c->use_h2)
|
||||
http2_stream_remove_mesh_state(r->h2_stream);
|
||||
comm_point_drop_reply(&r->query_reply);
|
||||
mstate->reply_list = reply_list;
|
||||
mstate->s.env->mesh->stats_dropped++;
|
||||
continue;
|
||||
}
|
||||
|
||||
i++;
|
||||
tv = r->start_time;
|
||||
|
||||
@@ -2179,6 +2298,9 @@ mesh_serve_expired_callback(void* arg)
|
||||
r, r_buffer, prev, prev_buffer);
|
||||
if(r->query_reply.c->tcp_req_info)
|
||||
tcp_req_info_remove_mesh_state(r->query_reply.c->tcp_req_info, mstate);
|
||||
/* mesh_send_reply removed mesh state from http2_stream. */
|
||||
infra_wait_limit_dec(mstate->s.env->infra_cache,
|
||||
&r->query_reply, mstate->s.env->cfg);
|
||||
prev = r;
|
||||
prev_buffer = r_buffer;
|
||||
}
|
||||
@@ -2225,6 +2347,14 @@ mesh_serve_expired_callback(void* arg)
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
mesh_respond_serve_expired(struct mesh_state* mstate)
|
||||
{
|
||||
if(!mstate->s.serve_expired_data)
|
||||
mesh_serve_expired_init(mstate, -1);
|
||||
mesh_serve_expired_callback(mstate);
|
||||
}
|
||||
|
||||
int mesh_jostle_exceeded(struct mesh_area* mesh)
|
||||
{
|
||||
if(mesh->all.count < mesh->max_reply_states)
|
||||
|
||||
@@ -690,4 +690,10 @@ mesh_serve_expired_lookup(struct module_qstate* qstate,
|
||||
*/
|
||||
int mesh_jostle_exceeded(struct mesh_area* mesh);
|
||||
|
||||
/**
|
||||
* Give the serve expired responses.
|
||||
* @param mstate: mesh state for query that has serve_expired_data.
|
||||
*/
|
||||
void mesh_respond_serve_expired(struct mesh_state* mstate);
|
||||
|
||||
#endif /* SERVICES_MESH_H */
|
||||
|
||||
+69
-9
@@ -95,6 +95,16 @@ modstack_init(struct module_stack* stack)
|
||||
stack->mod = NULL;
|
||||
}
|
||||
|
||||
void
|
||||
modstack_free(struct module_stack* stack)
|
||||
{
|
||||
if(!stack)
|
||||
return;
|
||||
stack->num = 0;
|
||||
free(stack->mod);
|
||||
stack->mod = NULL;
|
||||
}
|
||||
|
||||
int
|
||||
modstack_config(struct module_stack* stack, const char* module_conf)
|
||||
{
|
||||
@@ -222,18 +232,59 @@ module_func_block* module_factory(const char** str)
|
||||
return NULL;
|
||||
}
|
||||
|
||||
int
|
||||
modstack_setup(struct module_stack* stack, const char* module_conf,
|
||||
int
|
||||
modstack_call_startup(struct module_stack* stack, const char* module_conf,
|
||||
struct module_env* env)
|
||||
{
|
||||
int i;
|
||||
if(stack->num != 0)
|
||||
modstack_desetup(stack, env);
|
||||
fatal_exit("unexpected already initialised modules");
|
||||
/* fixed setup of the modules */
|
||||
if(!modstack_config(stack, module_conf)) {
|
||||
return 0;
|
||||
}
|
||||
for(i=0; i<stack->num; i++) {
|
||||
if(stack->mod[i]->startup == NULL)
|
||||
continue;
|
||||
verbose(VERB_OPS, "startup module %d: %s",
|
||||
i, stack->mod[i]->name);
|
||||
fptr_ok(fptr_whitelist_mod_startup(stack->mod[i]->startup));
|
||||
if(!(*stack->mod[i]->startup)(env, i)) {
|
||||
log_err("module startup for module %s failed",
|
||||
stack->mod[i]->name);
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
int
|
||||
modstack_call_init(struct module_stack* stack, const char* module_conf,
|
||||
struct module_env* env)
|
||||
{
|
||||
int i, changed = 0;
|
||||
env->need_to_validate = 0; /* set by module init below */
|
||||
for(i=0; i<stack->num; i++) {
|
||||
while(*module_conf && isspace(*module_conf))
|
||||
module_conf++;
|
||||
if(strncmp(stack->mod[i]->name, module_conf,
|
||||
strlen(stack->mod[i]->name))) {
|
||||
if(stack->mod[i]->startup || stack->mod[i]->destartup) {
|
||||
log_err("changed module ordering during reload not supported, for module that needs startup");
|
||||
return 0;
|
||||
} else {
|
||||
changed = 1;
|
||||
}
|
||||
}
|
||||
module_conf += strlen(stack->mod[i]->name);
|
||||
}
|
||||
if(changed) {
|
||||
modstack_free(stack);
|
||||
if(!modstack_config(stack, module_conf)) {
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
for(i=0; i<stack->num; i++) {
|
||||
verbose(VERB_OPS, "init module %d: %s",
|
||||
i, stack->mod[i]->name);
|
||||
@@ -247,20 +298,29 @@ modstack_setup(struct module_stack* stack, const char* module_conf,
|
||||
return 1;
|
||||
}
|
||||
|
||||
void
|
||||
modstack_desetup(struct module_stack* stack, struct module_env* env)
|
||||
void
|
||||
modstack_call_deinit(struct module_stack* stack, struct module_env* env)
|
||||
{
|
||||
int i;
|
||||
for(i=0; i<stack->num; i++) {
|
||||
fptr_ok(fptr_whitelist_mod_deinit(stack->mod[i]->deinit));
|
||||
(*stack->mod[i]->deinit)(env, i);
|
||||
}
|
||||
stack->num = 0;
|
||||
free(stack->mod);
|
||||
stack->mod = NULL;
|
||||
}
|
||||
|
||||
int
|
||||
void
|
||||
modstack_call_destartup(struct module_stack* stack, struct module_env* env)
|
||||
{
|
||||
int i;
|
||||
for(i=0; i<stack->num; i++) {
|
||||
if(stack->mod[i]->destartup == NULL)
|
||||
continue;
|
||||
fptr_ok(fptr_whitelist_mod_destartup(stack->mod[i]->destartup));
|
||||
(*stack->mod[i]->destartup)(env, i);
|
||||
}
|
||||
}
|
||||
|
||||
int
|
||||
modstack_find(struct module_stack* stack, const char* name)
|
||||
{
|
||||
int i;
|
||||
|
||||
+31
-7
@@ -60,6 +60,23 @@ struct module_stack {
|
||||
*/
|
||||
void modstack_init(struct module_stack* stack);
|
||||
|
||||
/**
|
||||
* Free the stack of modules
|
||||
* @param stack: stack that frees up memory.
|
||||
*/
|
||||
void modstack_free(struct module_stack* stack);
|
||||
|
||||
/**
|
||||
* Initialises modules and assignes ids. Calls module_startup().
|
||||
* @param stack: Expected empty, filled according to module_conf
|
||||
* @param module_conf: string what modules to initialize
|
||||
* @param env: module environment which is inited by the modules.
|
||||
* environment should have a superalloc, cfg,
|
||||
* @return on false a module init failed.
|
||||
*/
|
||||
int modstack_call_startup(struct module_stack* stack, const char* module_conf,
|
||||
struct module_env* env);
|
||||
|
||||
/**
|
||||
* Read config file module settings and set up the modfunc block
|
||||
* @param stack: the stack of modules (empty before call).
|
||||
@@ -83,24 +100,31 @@ struct module_func_block* module_factory(const char** str);
|
||||
const char** module_list_avail(void);
|
||||
|
||||
/**
|
||||
* Setup modules. Assigns ids and calls module_init.
|
||||
* @param stack: if not empty beforehand, it will be desetup()ed.
|
||||
* It is then modstack_configged().
|
||||
* @param module_conf: string what modules to insert.
|
||||
* Init modules. Calls module_init().
|
||||
* @param stack: It is modstack_setupped().
|
||||
* @param module_conf: module ordering to check against the ordering in stack.
|
||||
* fails on changed ordering.
|
||||
* @param env: module environment which is inited by the modules.
|
||||
* environment should have a superalloc, cfg,
|
||||
* env.need_to_validate is set by the modules.
|
||||
* @return on false a module init failed.
|
||||
*/
|
||||
int modstack_setup(struct module_stack* stack, const char* module_conf,
|
||||
int modstack_call_init(struct module_stack* stack, const char* module_conf,
|
||||
struct module_env* env);
|
||||
|
||||
/**
|
||||
* Desetup the modules, deinit, delete.
|
||||
* Deinit the modules.
|
||||
* @param stack: made empty.
|
||||
* @param env: module env for module deinit() calls.
|
||||
*/
|
||||
void modstack_desetup(struct module_stack* stack, struct module_env* env);
|
||||
void modstack_call_deinit(struct module_stack* stack, struct module_env* env);
|
||||
|
||||
/**
|
||||
* Destartup the modules, close, delete.
|
||||
* @param stack: made empty.
|
||||
* @param env: module env for module destartup() calls.
|
||||
*/
|
||||
void modstack_call_destartup(struct module_stack* stack, struct module_env* env);
|
||||
|
||||
/**
|
||||
* Find index of module by name.
|
||||
|
||||
+41
-22
@@ -550,7 +550,6 @@ reuse_tcp_find(struct outside_network* outnet, struct sockaddr_storage* addr,
|
||||
log_assert(&key_p.reuse != (struct reuse_tcp*)result);
|
||||
log_assert(&key_p != ((struct reuse_tcp*)result)->pending);
|
||||
}
|
||||
/* not found, return null */
|
||||
|
||||
/* It is possible that we search for something before the first element
|
||||
* in the tree. Replace a null pointer with the first element.
|
||||
@@ -560,6 +559,7 @@ reuse_tcp_find(struct outside_network* outnet, struct sockaddr_storage* addr,
|
||||
result = rbtree_first(&outnet->tcp_reuse);
|
||||
}
|
||||
|
||||
/* not found, return null */
|
||||
if(!result || result == RBTREE_NULL)
|
||||
return NULL;
|
||||
|
||||
@@ -1009,7 +1009,7 @@ use_free_buffer(struct outside_network* outnet)
|
||||
sldns_buffer tmp;
|
||||
sldns_buffer_init_frm_data(&tmp, w->pkt, w->pkt_len);
|
||||
dt_msg_send_outside_query(outnet->dtenv, &w->sq->addr,
|
||||
&pend_tcp->pi->addr, comm_tcp, w->sq->zone,
|
||||
&pend_tcp->pi->addr, comm_tcp, NULL, w->sq->zone,
|
||||
w->sq->zonelen, &tmp);
|
||||
}
|
||||
#endif
|
||||
@@ -2051,7 +2051,8 @@ select_id(struct outside_network* outnet, struct pending* pend,
|
||||
}
|
||||
|
||||
/** return true is UDP connect error needs to be logged */
|
||||
static int udp_connect_needs_log(int err)
|
||||
static int udp_connect_needs_log(int err, struct sockaddr_storage* addr,
|
||||
socklen_t addrlen)
|
||||
{
|
||||
switch(err) {
|
||||
case ECONNREFUSED:
|
||||
@@ -2075,6 +2076,15 @@ static int udp_connect_needs_log(int err)
|
||||
if(verbosity >= VERB_ALGO)
|
||||
return 1;
|
||||
return 0;
|
||||
case EINVAL:
|
||||
/* Stop 'Invalid argument for fe80::/10' addresses appearing
|
||||
* in the logs, at low verbosity. They cannot be sent to. */
|
||||
if(addr_is_ip6linklocal(addr, addrlen)) {
|
||||
if(verbosity >= VERB_ALGO)
|
||||
return 1;
|
||||
return 0;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
@@ -2141,7 +2151,8 @@ select_ifport(struct outside_network* outnet, struct pending* pend,
|
||||
/* connect() to the destination */
|
||||
if(connect(fd, (struct sockaddr*)&pend->addr,
|
||||
pend->addrlen) < 0) {
|
||||
if(udp_connect_needs_log(errno)) {
|
||||
if(udp_connect_needs_log(errno,
|
||||
&pend->addr, pend->addrlen)) {
|
||||
log_err_addr("udp connect failed",
|
||||
strerror(errno), &pend->addr,
|
||||
pend->addrlen);
|
||||
@@ -2237,7 +2248,7 @@ randomize_and_send_udp(struct pending* pend, sldns_buffer* packet, int timeout)
|
||||
outnet->dtenv->log_forwarder_query_messages)) {
|
||||
log_addr(VERB_ALGO, "from local addr", &pend->pc->pif->addr, pend->pc->pif->addrlen);
|
||||
log_addr(VERB_ALGO, "request to upstream", &pend->addr, pend->addrlen);
|
||||
dt_msg_send_outside_query(outnet->dtenv, &pend->addr, &pend->pc->pif->addr, comm_udp,
|
||||
dt_msg_send_outside_query(outnet->dtenv, &pend->addr, &pend->pc->pif->addr, comm_udp, NULL,
|
||||
pend->sq->zone, pend->sq->zonelen, packet);
|
||||
}
|
||||
#endif
|
||||
@@ -2517,7 +2528,7 @@ pending_tcp_query(struct serviced_query* sq, sldns_buffer* packet,
|
||||
sldns_buffer tmp;
|
||||
sldns_buffer_init_frm_data(&tmp, w->pkt, w->pkt_len);
|
||||
dt_msg_send_outside_query(sq->outnet->dtenv, &sq->addr,
|
||||
&pend->pi->addr, comm_tcp, sq->zone,
|
||||
&pend->pi->addr, comm_tcp, NULL, sq->zone,
|
||||
sq->zonelen, &tmp);
|
||||
}
|
||||
#endif
|
||||
@@ -2820,6 +2831,25 @@ serviced_perturb_qname(struct ub_randstate* rnd, uint8_t* qbuf, size_t len)
|
||||
}
|
||||
}
|
||||
|
||||
static uint16_t
|
||||
serviced_query_udp_size(struct serviced_query* sq, enum serviced_query_status status) {
|
||||
uint16_t udp_size;
|
||||
if(status == serviced_query_UDP_EDNS_FRAG) {
|
||||
if(addr_is_ip6(&sq->addr, sq->addrlen)) {
|
||||
if(EDNS_FRAG_SIZE_IP6 < EDNS_ADVERTISED_SIZE)
|
||||
udp_size = EDNS_FRAG_SIZE_IP6;
|
||||
else udp_size = EDNS_ADVERTISED_SIZE;
|
||||
} else {
|
||||
if(EDNS_FRAG_SIZE_IP4 < EDNS_ADVERTISED_SIZE)
|
||||
udp_size = EDNS_FRAG_SIZE_IP4;
|
||||
else udp_size = EDNS_ADVERTISED_SIZE;
|
||||
}
|
||||
} else {
|
||||
udp_size = EDNS_ADVERTISED_SIZE;
|
||||
}
|
||||
return udp_size;
|
||||
}
|
||||
|
||||
/** put serviced query into a buffer */
|
||||
static void
|
||||
serviced_encode(struct serviced_query* sq, sldns_buffer* buff, int with_edns)
|
||||
@@ -2843,19 +2873,7 @@ serviced_encode(struct serviced_query* sq, sldns_buffer* buff, int with_edns)
|
||||
edns.opt_list_in = NULL;
|
||||
edns.opt_list_out = sq->opt_list;
|
||||
edns.opt_list_inplace_cb_out = NULL;
|
||||
if(sq->status == serviced_query_UDP_EDNS_FRAG) {
|
||||
if(addr_is_ip6(&sq->addr, sq->addrlen)) {
|
||||
if(EDNS_FRAG_SIZE_IP6 < EDNS_ADVERTISED_SIZE)
|
||||
edns.udp_size = EDNS_FRAG_SIZE_IP6;
|
||||
else edns.udp_size = EDNS_ADVERTISED_SIZE;
|
||||
} else {
|
||||
if(EDNS_FRAG_SIZE_IP4 < EDNS_ADVERTISED_SIZE)
|
||||
edns.udp_size = EDNS_FRAG_SIZE_IP4;
|
||||
else edns.udp_size = EDNS_ADVERTISED_SIZE;
|
||||
}
|
||||
} else {
|
||||
edns.udp_size = EDNS_ADVERTISED_SIZE;
|
||||
}
|
||||
edns.udp_size = serviced_query_udp_size(sq, sq->status);
|
||||
edns.bits = 0;
|
||||
if(sq->dnssec & EDNS_DO)
|
||||
edns.bits = EDNS_DO;
|
||||
@@ -3083,7 +3101,7 @@ serviced_tcp_callback(struct comm_point* c, void* arg, int error,
|
||||
log_addr(VERB_ALGO, "response from upstream", &sq->addr, sq->addrlen);
|
||||
log_addr(VERB_ALGO, "to local addr", &pi->addr, pi->addrlen);
|
||||
dt_msg_send_outside_response(sq->outnet->dtenv, &sq->addr,
|
||||
&pi->addr, c->type, sq->zone, sq->zonelen, sq->qbuf,
|
||||
&pi->addr, c->type, c->ssl, sq->zone, sq->zonelen, sq->qbuf,
|
||||
sq->qbuflen, &sq->last_sent_time, sq->outnet->now_tv,
|
||||
c->buffer);
|
||||
}
|
||||
@@ -3252,7 +3270,8 @@ serviced_udp_callback(struct comm_point* c, void* arg, int error,
|
||||
|
||||
sq->pending = NULL; /* removed after callback */
|
||||
if(error == NETEVENT_TIMEOUT) {
|
||||
if(sq->status == serviced_query_UDP_EDNS && sq->last_rtt < 5000) {
|
||||
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 */
|
||||
sq->status = serviced_query_UDP_EDNS_FRAG;
|
||||
log_name_addr(VERB_ALGO, "try edns1xx0", sq->qbuf+10,
|
||||
@@ -3296,7 +3315,7 @@ serviced_udp_callback(struct comm_point* c, void* arg, int error,
|
||||
log_addr(VERB_ALGO, "to local addr", &p->pc->pif->addr,
|
||||
p->pc->pif->addrlen);
|
||||
dt_msg_send_outside_response(outnet->dtenv, &sq->addr,
|
||||
&p->pc->pif->addr, c->type, sq->zone, sq->zonelen,
|
||||
&p->pc->pif->addr, c->type, c->ssl, sq->zone, sq->zonelen,
|
||||
sq->qbuf, sq->qbuflen, &sq->last_sent_time,
|
||||
sq->outnet->now_tv, c->buffer);
|
||||
}
|
||||
|
||||
+270
-99
@@ -478,6 +478,67 @@ new_cname_override(struct regional* region, uint8_t* ct, size_t ctlen)
|
||||
return rrset;
|
||||
}
|
||||
|
||||
/** delete the cname override */
|
||||
static void
|
||||
delete_cname_override(struct rpz* r)
|
||||
{
|
||||
if(r->cname_override) {
|
||||
/* The cname override is what is allocated in the region. */
|
||||
regional_free_all(r->region);
|
||||
r->cname_override = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
/** Apply rpz config elements to the rpz structure, false on failure. */
|
||||
static int
|
||||
rpz_apply_cfg_elements(struct rpz* r, struct config_auth* p)
|
||||
{
|
||||
if(p->rpz_taglist && p->rpz_taglistlen) {
|
||||
r->taglistlen = p->rpz_taglistlen;
|
||||
r->taglist = memdup(p->rpz_taglist, r->taglistlen);
|
||||
if(!r->taglist) {
|
||||
log_err("malloc failure on RPZ taglist alloc");
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
if(p->rpz_action_override) {
|
||||
r->action_override = rpz_config_to_action(p->rpz_action_override);
|
||||
}
|
||||
else
|
||||
r->action_override = RPZ_NO_OVERRIDE_ACTION;
|
||||
|
||||
if(r->action_override == RPZ_CNAME_OVERRIDE_ACTION) {
|
||||
uint8_t nm[LDNS_MAX_DOMAINLEN+1];
|
||||
size_t nmlen = sizeof(nm);
|
||||
|
||||
if(!p->rpz_cname) {
|
||||
log_err("rpz: override with cname action found, but no "
|
||||
"rpz-cname-override configured");
|
||||
return 0;
|
||||
}
|
||||
|
||||
if(sldns_str2wire_dname_buf(p->rpz_cname, nm, &nmlen) != 0) {
|
||||
log_err("rpz: cannot parse cname override: %s",
|
||||
p->rpz_cname);
|
||||
return 0;
|
||||
}
|
||||
r->cname_override = new_cname_override(r->region, nm, nmlen);
|
||||
if(!r->cname_override) {
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
r->log = p->rpz_log;
|
||||
r->signal_nxdomain_ra = p->rpz_signal_nxdomain_ra;
|
||||
if(p->rpz_log_name) {
|
||||
if(!(r->log_name = strdup(p->rpz_log_name))) {
|
||||
log_err("malloc failure on RPZ log_name strdup");
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
struct rpz*
|
||||
rpz_create(struct config_auth* p)
|
||||
{
|
||||
@@ -513,42 +574,8 @@ rpz_create(struct config_auth* p)
|
||||
goto err;
|
||||
}
|
||||
|
||||
r->taglistlen = p->rpz_taglistlen;
|
||||
r->taglist = memdup(p->rpz_taglist, r->taglistlen);
|
||||
if(p->rpz_action_override) {
|
||||
r->action_override = rpz_config_to_action(p->rpz_action_override);
|
||||
}
|
||||
else
|
||||
r->action_override = RPZ_NO_OVERRIDE_ACTION;
|
||||
|
||||
if(r->action_override == RPZ_CNAME_OVERRIDE_ACTION) {
|
||||
uint8_t nm[LDNS_MAX_DOMAINLEN+1];
|
||||
size_t nmlen = sizeof(nm);
|
||||
|
||||
if(!p->rpz_cname) {
|
||||
log_err("rpz: override with cname action found, but no "
|
||||
"rpz-cname-override configured");
|
||||
goto err;
|
||||
}
|
||||
|
||||
if(sldns_str2wire_dname_buf(p->rpz_cname, nm, &nmlen) != 0) {
|
||||
log_err("rpz: cannot parse cname override: %s",
|
||||
p->rpz_cname);
|
||||
goto err;
|
||||
}
|
||||
r->cname_override = new_cname_override(r->region, nm, nmlen);
|
||||
if(!r->cname_override) {
|
||||
goto err;
|
||||
}
|
||||
}
|
||||
r->log = p->rpz_log;
|
||||
r->signal_nxdomain_ra = p->rpz_signal_nxdomain_ra;
|
||||
if(p->rpz_log_name) {
|
||||
if(!(r->log_name = strdup(p->rpz_log_name))) {
|
||||
log_err("malloc failure on RPZ log_name strdup");
|
||||
goto err;
|
||||
}
|
||||
}
|
||||
if(!rpz_apply_cfg_elements(r, p))
|
||||
goto err;
|
||||
return r;
|
||||
err:
|
||||
if(r) {
|
||||
@@ -571,6 +598,32 @@ err:
|
||||
return NULL;
|
||||
}
|
||||
|
||||
int
|
||||
rpz_config(struct rpz* r, struct config_auth* p)
|
||||
{
|
||||
/* If the zonefile changes, it is read later, after which
|
||||
* rpz_clear and rpz_finish_config is called. */
|
||||
|
||||
/* free taglist, if any */
|
||||
if(r->taglist) {
|
||||
free(r->taglist);
|
||||
r->taglist = NULL;
|
||||
r->taglistlen = 0;
|
||||
}
|
||||
|
||||
/* free logname, if any */
|
||||
if(r->log_name) {
|
||||
free(r->log_name);
|
||||
r->log_name = NULL;
|
||||
}
|
||||
|
||||
delete_cname_override(r);
|
||||
|
||||
if(!rpz_apply_cfg_elements(r, p))
|
||||
return 0;
|
||||
return 1;
|
||||
}
|
||||
|
||||
/**
|
||||
* Remove RPZ zone name from dname
|
||||
* Copy dname to newdname, without the originlen number of trailing bytes
|
||||
@@ -1191,16 +1244,20 @@ rpz_find_zone(struct local_zones* zones, uint8_t* qname, size_t qname_len, uint1
|
||||
/** Find entry for RR type in the list of rrsets for the clientip. */
|
||||
static struct local_rrset*
|
||||
rpz_find_synthesized_rrset(uint16_t qtype,
|
||||
struct clientip_synthesized_rr* data)
|
||||
struct clientip_synthesized_rr* data, int alias_ok)
|
||||
{
|
||||
struct local_rrset* cursor = data->data;
|
||||
struct local_rrset* cursor = data->data, *cname = NULL;
|
||||
while( cursor != NULL) {
|
||||
struct packed_rrset_key* packed_rrset = &cursor->rrset->rk;
|
||||
if(htons(qtype) == packed_rrset->type) {
|
||||
return cursor;
|
||||
}
|
||||
if(ntohs(packed_rrset->type) == LDNS_RR_TYPE_CNAME && alias_ok)
|
||||
cname = cursor;
|
||||
cursor = cursor->next;
|
||||
}
|
||||
if(alias_ok)
|
||||
return cname;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
@@ -1386,7 +1443,7 @@ static int rpz_remove_clientip_rr(struct clientip_synthesized_rr* node,
|
||||
struct local_rrset* rrset;
|
||||
struct packed_rrset_data* d;
|
||||
size_t index;
|
||||
rrset = rpz_find_synthesized_rrset(rr_type, node);
|
||||
rrset = rpz_find_synthesized_rrset(rr_type, node, 0);
|
||||
if(rrset == NULL)
|
||||
return 0; /* type not found, ignore */
|
||||
d = (struct packed_rrset_data*)rrset->rrset->entry.data;
|
||||
@@ -1789,7 +1846,7 @@ rpz_apply_clientip_localdata_action(struct clientip_synthesized_rr* raddr,
|
||||
}
|
||||
|
||||
/* check query type / rr type */
|
||||
rrset = rpz_find_synthesized_rrset(qinfo->qtype, raddr);
|
||||
rrset = rpz_find_synthesized_rrset(qinfo->qtype, raddr, 1);
|
||||
if(rrset == NULL) {
|
||||
verbose(VERB_ALGO, "rpz: unable to find local-data for query");
|
||||
rrset_count = 0;
|
||||
@@ -1823,6 +1880,28 @@ nodata:
|
||||
rrset_count, rcode, rsoa);
|
||||
}
|
||||
|
||||
/** Apply the cname override action, during worker request callback.
|
||||
* false on failure. */
|
||||
static int
|
||||
rpz_apply_cname_override_action(struct rpz* r,
|
||||
struct query_info* qinfo, struct regional* temp)
|
||||
{
|
||||
if(!r)
|
||||
return 0;
|
||||
qinfo->local_alias = regional_alloc_zero(temp,
|
||||
sizeof(struct local_rrset));
|
||||
if(qinfo->local_alias == NULL)
|
||||
return 0; /* out of memory */
|
||||
qinfo->local_alias->rrset = respip_copy_rrset(r->cname_override, temp);
|
||||
if(qinfo->local_alias->rrset == NULL) {
|
||||
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;
|
||||
return 1;
|
||||
}
|
||||
|
||||
/** add additional section SOA record to the reply.
|
||||
* Since this gets fed into the normal iterator answer creation, it
|
||||
* gets minimal-responses applied to it, that can remove the additional SOA
|
||||
@@ -1933,6 +2012,7 @@ rpz_synthesize_localdata_from_rrset(struct rpz* ATTR_UNUSED(r), struct module_qs
|
||||
msg = rpz_dns_msg_new(ms->region);
|
||||
if(msg == NULL) { return NULL; }
|
||||
|
||||
msg->qinfo = *qi;
|
||||
new_reply_info = construct_reply_info_base(ms->region,
|
||||
LDNS_RCODE_NOERROR | BIT_QR | BIT_AA | BIT_RA,
|
||||
1, /* qd */
|
||||
@@ -1975,40 +2055,42 @@ rpz_synthesize_localdata_from_rrset(struct rpz* ATTR_UNUSED(r), struct module_qs
|
||||
|
||||
static inline struct dns_msg*
|
||||
rpz_synthesize_nsip_localdata(struct rpz* r, struct module_qstate* ms,
|
||||
struct clientip_synthesized_rr* data, struct auth_zone* az)
|
||||
struct query_info* qi, struct clientip_synthesized_rr* data,
|
||||
struct auth_zone* az)
|
||||
{
|
||||
struct query_info* qi = &ms->qinfo;
|
||||
struct local_rrset* rrset;
|
||||
|
||||
rrset = rpz_find_synthesized_rrset(qi->qtype, data);
|
||||
rrset = rpz_find_synthesized_rrset(qi->qtype, data, 1);
|
||||
if(rrset == NULL) {
|
||||
verbose(VERB_ALGO, "rpz: nsip: no matching local data found");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
return rpz_synthesize_localdata_from_rrset(r, ms, &ms->qinfo, rrset, az);
|
||||
return rpz_synthesize_localdata_from_rrset(r, ms, qi, rrset, az);
|
||||
}
|
||||
|
||||
/* copy'n'paste from localzone.c */
|
||||
static struct local_rrset*
|
||||
local_data_find_type(struct local_data* data, uint16_t type, int alias_ok)
|
||||
{
|
||||
struct local_rrset* p;
|
||||
struct local_rrset* p, *cname = NULL;
|
||||
type = htons(type);
|
||||
for(p = data->rrsets; p; p = p->next) {
|
||||
if(p->rrset->rk.type == type)
|
||||
return p;
|
||||
if(alias_ok && p->rrset->rk.type == htons(LDNS_RR_TYPE_CNAME))
|
||||
return p;
|
||||
cname = p;
|
||||
}
|
||||
if(alias_ok)
|
||||
return cname;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/* based on localzone.c:local_data_answer() */
|
||||
static inline struct dns_msg*
|
||||
rpz_synthesize_nsdname_localdata(struct rpz* r, struct module_qstate* ms,
|
||||
struct local_zone* z, struct matched_delegation_point const* match,
|
||||
struct auth_zone* az)
|
||||
struct query_info* qi, struct local_zone* z,
|
||||
struct matched_delegation_point const* match, struct auth_zone* az)
|
||||
{
|
||||
struct local_data key;
|
||||
struct local_data* ld;
|
||||
@@ -2029,13 +2111,13 @@ rpz_synthesize_nsdname_localdata(struct rpz* r, struct module_qstate* ms,
|
||||
return NULL;
|
||||
}
|
||||
|
||||
rrset = local_data_find_type(ld, ms->qinfo.qtype, 1);
|
||||
rrset = local_data_find_type(ld, qi->qtype, 1);
|
||||
if(rrset == NULL) {
|
||||
verbose(VERB_ALGO, "rpz: nsdname: no matching local data found");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
return rpz_synthesize_localdata_from_rrset(r, ms, &ms->qinfo, rrset, az);
|
||||
return rpz_synthesize_localdata_from_rrset(r, ms, qi, rrset, az);
|
||||
}
|
||||
|
||||
/* like local_data_answer for qname triggers after a cname */
|
||||
@@ -2052,17 +2134,70 @@ rpz_synthesize_qname_localdata_msg(struct rpz* r, struct module_qstate* ms,
|
||||
key.namelabs = dname_count_labels(qinfo->qname);
|
||||
ld = (struct local_data*)rbtree_search(&z->data, &key.node);
|
||||
if(ld == NULL) {
|
||||
verbose(VERB_ALGO, "rpz: qname after cname: name not found");
|
||||
verbose(VERB_ALGO, "rpz: qname: name not found");
|
||||
return NULL;
|
||||
}
|
||||
rrset = local_data_find_type(ld, qinfo->qtype, 1);
|
||||
if(rrset == NULL) {
|
||||
verbose(VERB_ALGO, "rpz: qname after cname: type not found");
|
||||
verbose(VERB_ALGO, "rpz: qname: type not found");
|
||||
return NULL;
|
||||
}
|
||||
return rpz_synthesize_localdata_from_rrset(r, ms, qinfo, rrset, az);
|
||||
}
|
||||
|
||||
/** Synthesize a CNAME message for RPZ action override */
|
||||
static struct dns_msg*
|
||||
rpz_synthesize_cname_override_msg(struct rpz* r, struct module_qstate* ms,
|
||||
struct query_info* qinfo)
|
||||
{
|
||||
struct dns_msg* msg = NULL;
|
||||
struct reply_info* new_reply_info;
|
||||
struct ub_packed_rrset_key* rp;
|
||||
|
||||
msg = rpz_dns_msg_new(ms->region);
|
||||
if(msg == NULL) { return NULL; }
|
||||
|
||||
msg->qinfo = *qinfo;
|
||||
new_reply_info = construct_reply_info_base(ms->region,
|
||||
LDNS_RCODE_NOERROR | BIT_QR | BIT_AA | BIT_RA,
|
||||
1, /* qd */
|
||||
0, /* ttl */
|
||||
0, /* prettl */
|
||||
0, /* expttl */
|
||||
1, /* an */
|
||||
0, /* ns */
|
||||
0, /* ar */
|
||||
1, /* total */
|
||||
sec_status_insecure,
|
||||
LDNS_EDE_NONE);
|
||||
if(new_reply_info == NULL) {
|
||||
log_err("out of memory");
|
||||
return NULL;
|
||||
}
|
||||
new_reply_info->authoritative = 1;
|
||||
|
||||
rp = respip_copy_rrset(r->cname_override, ms->region);
|
||||
if(rp == NULL) {
|
||||
log_err("out of memory");
|
||||
return NULL;
|
||||
}
|
||||
rp->rk.dname = qinfo->qname;
|
||||
rp->rk.dname_len = qinfo->qname_len;
|
||||
/* this rrset is from the rpz data, or synthesized.
|
||||
* It is not actually from the network, so we flag it with this
|
||||
* flags as a fake RRset. If later the cache is used to look up
|
||||
* rrsets, then the fake ones are not returned (if you look without
|
||||
* the flag). For like CNAME lookups from the iterator or A, AAAA
|
||||
* lookups for nameserver targets, it would use the without flag
|
||||
* actual data. So that the actual network data and fake data
|
||||
* are kept track of separately. */
|
||||
rp->rk.flags |= PACKED_RRSET_RPZ;
|
||||
new_reply_info->rrsets[0] = rp;
|
||||
|
||||
msg->rep = new_reply_info;
|
||||
return msg;
|
||||
}
|
||||
|
||||
static int
|
||||
rpz_synthesize_qname_localdata(struct module_env* env, struct rpz* r,
|
||||
struct local_zone* z, enum localzone_type lzt, struct query_info* qinfo,
|
||||
@@ -2072,17 +2207,8 @@ rpz_synthesize_qname_localdata(struct module_env* env, struct rpz* r,
|
||||
struct local_data* ld = NULL;
|
||||
int ret = 0;
|
||||
if(r->action_override == RPZ_CNAME_OVERRIDE_ACTION) {
|
||||
qinfo->local_alias = regional_alloc_zero(temp, sizeof(struct local_rrset));
|
||||
if(qinfo->local_alias == NULL) {
|
||||
return 0; /* out of memory */
|
||||
}
|
||||
qinfo->local_alias->rrset = regional_alloc_init(temp, r->cname_override,
|
||||
sizeof(*r->cname_override));
|
||||
if(qinfo->local_alias->rrset == NULL) {
|
||||
return 0; /* out of memory */
|
||||
}
|
||||
qinfo->local_alias->rrset->rk.dname = qinfo->qname;
|
||||
qinfo->local_alias->rrset->rk.dname_len = qinfo->qname_len;
|
||||
if(!rpz_apply_cname_override_action(r, qinfo, temp))
|
||||
return 0;
|
||||
if(r->log) {
|
||||
log_rpz_apply("qname", z->name, NULL, RPZ_CNAME_OVERRIDE_ACTION,
|
||||
qinfo, repinfo, NULL, r->log_name);
|
||||
@@ -2134,8 +2260,9 @@ rpz_delegation_point_ipbased_trigger_lookup(struct rpz* rpz, struct iter_qstate*
|
||||
}
|
||||
|
||||
static struct dns_msg*
|
||||
rpz_apply_nsip_trigger(struct module_qstate* ms, struct rpz* r,
|
||||
struct clientip_synthesized_rr* raddr, struct auth_zone* az)
|
||||
rpz_apply_nsip_trigger(struct module_qstate* ms, struct query_info* qchase,
|
||||
struct rpz* r, struct clientip_synthesized_rr* raddr,
|
||||
struct auth_zone* az)
|
||||
{
|
||||
enum rpz_action action = raddr->action;
|
||||
struct dns_msg* ret = NULL;
|
||||
@@ -2148,35 +2275,38 @@ rpz_apply_nsip_trigger(struct module_qstate* ms, struct rpz* r,
|
||||
|
||||
if(action == RPZ_LOCAL_DATA_ACTION && raddr->data == NULL) {
|
||||
verbose(VERB_ALGO, "rpz: bug: nsip local data action but no local data");
|
||||
ret = rpz_synthesize_nodata(r, ms, &ms->qinfo, az);
|
||||
ret = rpz_synthesize_nodata(r, ms, qchase, az);
|
||||
goto done;
|
||||
}
|
||||
|
||||
switch(action) {
|
||||
case RPZ_NXDOMAIN_ACTION:
|
||||
ret = rpz_synthesize_nxdomain(r, ms, &ms->qinfo, az);
|
||||
ret = rpz_synthesize_nxdomain(r, ms, qchase, az);
|
||||
break;
|
||||
case RPZ_NODATA_ACTION:
|
||||
ret = rpz_synthesize_nodata(r, ms, &ms->qinfo, az);
|
||||
ret = rpz_synthesize_nodata(r, ms, qchase, az);
|
||||
break;
|
||||
case RPZ_TCP_ONLY_ACTION:
|
||||
/* basically a passthru here but the tcp-only will be
|
||||
* honored before the query gets sent. */
|
||||
ms->respip_action_info->action = respip_truncate;
|
||||
ms->tcp_required = 1;
|
||||
ret = NULL;
|
||||
break;
|
||||
case RPZ_DROP_ACTION:
|
||||
ret = rpz_synthesize_nodata(r, ms, &ms->qinfo, az);
|
||||
ret = rpz_synthesize_nodata(r, ms, qchase, az);
|
||||
ms->is_drop = 1;
|
||||
break;
|
||||
case RPZ_LOCAL_DATA_ACTION:
|
||||
ret = rpz_synthesize_nsip_localdata(r, ms, raddr, az);
|
||||
if(ret == NULL) { ret = rpz_synthesize_nodata(r, ms, &ms->qinfo, az); }
|
||||
ret = rpz_synthesize_nsip_localdata(r, ms, qchase, raddr, az);
|
||||
if(ret == NULL) { ret = rpz_synthesize_nodata(r, ms, qchase, az); }
|
||||
break;
|
||||
case RPZ_PASSTHRU_ACTION:
|
||||
ret = NULL;
|
||||
ms->rpz_passthru = 1;
|
||||
break;
|
||||
case RPZ_CNAME_OVERRIDE_ACTION:
|
||||
ret = rpz_synthesize_cname_override_msg(r, ms, qchase);
|
||||
break;
|
||||
default:
|
||||
verbose(VERB_ALGO, "rpz: nsip: bug: unhandled or invalid action: '%s'",
|
||||
rpz_action_to_string(action));
|
||||
@@ -2194,9 +2324,9 @@ done:
|
||||
}
|
||||
|
||||
static struct dns_msg*
|
||||
rpz_apply_nsdname_trigger(struct module_qstate* ms, struct rpz* r,
|
||||
struct local_zone* z, struct matched_delegation_point const* match,
|
||||
struct auth_zone* az)
|
||||
rpz_apply_nsdname_trigger(struct module_qstate* ms, struct query_info* qchase,
|
||||
struct rpz* r, struct local_zone* z,
|
||||
struct matched_delegation_point const* match, struct auth_zone* az)
|
||||
{
|
||||
struct dns_msg* ret = NULL;
|
||||
enum rpz_action action = localzone_type_to_rpz_action(z->type);
|
||||
@@ -2209,31 +2339,34 @@ rpz_apply_nsdname_trigger(struct module_qstate* ms, struct rpz* r,
|
||||
|
||||
switch(action) {
|
||||
case RPZ_NXDOMAIN_ACTION:
|
||||
ret = rpz_synthesize_nxdomain(r, ms, &ms->qinfo, az);
|
||||
ret = rpz_synthesize_nxdomain(r, ms, qchase, az);
|
||||
break;
|
||||
case RPZ_NODATA_ACTION:
|
||||
ret = rpz_synthesize_nodata(r, ms, &ms->qinfo, az);
|
||||
ret = rpz_synthesize_nodata(r, ms, qchase, az);
|
||||
break;
|
||||
case RPZ_TCP_ONLY_ACTION:
|
||||
/* basically a passthru here but the tcp-only will be
|
||||
* honored before the query gets sent. */
|
||||
ms->respip_action_info->action = respip_truncate;
|
||||
ms->tcp_required = 1;
|
||||
ret = NULL;
|
||||
break;
|
||||
case RPZ_DROP_ACTION:
|
||||
ret = rpz_synthesize_nodata(r, ms, &ms->qinfo, az);
|
||||
ret = rpz_synthesize_nodata(r, ms, qchase, az);
|
||||
ms->is_drop = 1;
|
||||
break;
|
||||
case RPZ_LOCAL_DATA_ACTION:
|
||||
ret = rpz_synthesize_nsdname_localdata(r, ms, z, match, az);
|
||||
if(ret == NULL) { ret = rpz_synthesize_nodata(r, ms, &ms->qinfo, az); }
|
||||
ret = rpz_synthesize_nsdname_localdata(r, ms, qchase, z, match, az);
|
||||
if(ret == NULL) { ret = rpz_synthesize_nodata(r, ms, qchase, az); }
|
||||
break;
|
||||
case RPZ_PASSTHRU_ACTION:
|
||||
ret = NULL;
|
||||
ms->rpz_passthru = 1;
|
||||
break;
|
||||
case RPZ_CNAME_OVERRIDE_ACTION:
|
||||
ret = rpz_synthesize_cname_override_msg(r, ms, qchase);
|
||||
break;
|
||||
default:
|
||||
verbose(VERB_ALGO, "rpz: nsip: bug: unhandled or invalid action: '%s'",
|
||||
verbose(VERB_ALGO, "rpz: nsdname: bug: unhandled or invalid action: '%s'",
|
||||
rpz_action_to_string(action));
|
||||
ret = NULL;
|
||||
}
|
||||
@@ -2302,11 +2435,10 @@ rpz_callback_from_iterator_module(struct module_qstate* ms, struct iter_qstate*
|
||||
if(ms->env == NULL || ms->env->auth_zones == NULL) { return 0; }
|
||||
|
||||
az = ms->env->auth_zones;
|
||||
lock_rw_rdlock(&az->rpz_lock);
|
||||
|
||||
verbose(VERB_ALGO, "rpz: iterator module callback: have_rpz=%d", az->rpz_first != NULL);
|
||||
|
||||
lock_rw_rdlock(&az->rpz_lock);
|
||||
|
||||
/* precedence of RPZ works, loosely, like this:
|
||||
* CNAMEs in order of the CNAME chain. rpzs in the order they are
|
||||
* configured. In an RPZ: first client-IP addr, then QNAME, then
|
||||
@@ -2321,10 +2453,17 @@ rpz_callback_from_iterator_module(struct module_qstate* ms, struct iter_qstate*
|
||||
lock_rw_unlock(&a->lock);
|
||||
continue;
|
||||
}
|
||||
if(r->taglist && (!ms->client_info ||
|
||||
!taglist_intersect(r->taglist, r->taglistlen,
|
||||
ms->client_info->taglist,
|
||||
ms->client_info->taglen))) {
|
||||
lock_rw_unlock(&a->lock);
|
||||
continue;
|
||||
}
|
||||
|
||||
/* the nsdname has precedence over the nsip triggers */
|
||||
z = rpz_delegation_point_zone_lookup(is->dp, r->nsdname_zones,
|
||||
ms->qinfo.qclass, &match);
|
||||
is->qchase.qclass, &match);
|
||||
if(z != NULL) {
|
||||
lock_rw_unlock(&a->lock);
|
||||
break;
|
||||
@@ -2347,9 +2486,9 @@ 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, r, raddr, a);
|
||||
return rpz_apply_nsip_trigger(ms, &is->qchase, r, raddr, a);
|
||||
}
|
||||
return rpz_apply_nsdname_trigger(ms, r, z, &match, a);
|
||||
return rpz_apply_nsdname_trigger(ms, &is->qchase, r, z, &match, a);
|
||||
}
|
||||
|
||||
struct dns_msg* rpz_callback_from_iterator_cname(struct module_qstate* ms,
|
||||
@@ -2379,6 +2518,13 @@ struct dns_msg* rpz_callback_from_iterator_cname(struct module_qstate* ms,
|
||||
lock_rw_unlock(&a->lock);
|
||||
continue;
|
||||
}
|
||||
if(r->taglist && (!ms->client_info ||
|
||||
!taglist_intersect(r->taglist, r->taglistlen,
|
||||
ms->client_info->taglist,
|
||||
ms->client_info->taglen))) {
|
||||
lock_rw_unlock(&a->lock);
|
||||
continue;
|
||||
}
|
||||
z = rpz_find_zone(r->local_zones, is->qchase.qname,
|
||||
is->qchase.qname_len, is->qchase.qclass, 0, 0, 0);
|
||||
if(z && r->action_override == RPZ_DISABLED_ACTION) {
|
||||
@@ -2412,10 +2558,10 @@ struct dns_msg* rpz_callback_from_iterator_cname(struct module_qstate* ms,
|
||||
dname_str(is->qchase.qname, nm);
|
||||
dname_str(z->name, zn);
|
||||
if(strcmp(zn, nm) != 0)
|
||||
verbose(VERB_ALGO, "rpz: qname trigger after cname %s on %s, with action=%s",
|
||||
verbose(VERB_ALGO, "rpz: qname trigger %s on %s, with action=%s",
|
||||
zn, nm, rpz_action_to_string(localzone_type_to_rpz_action(lzt)));
|
||||
else
|
||||
verbose(VERB_ALGO, "rpz: qname trigger after cname %s, with action=%s",
|
||||
verbose(VERB_ALGO, "rpz: qname trigger %s, with action=%s",
|
||||
nm, rpz_action_to_string(localzone_type_to_rpz_action(lzt)));
|
||||
}
|
||||
switch(localzone_type_to_rpz_action(lzt)) {
|
||||
@@ -2428,7 +2574,7 @@ struct dns_msg* rpz_callback_from_iterator_cname(struct module_qstate* ms,
|
||||
case RPZ_TCP_ONLY_ACTION:
|
||||
/* basically a passthru here but the tcp-only will be
|
||||
* honored before the query gets sent. */
|
||||
ms->respip_action_info->action = respip_truncate;
|
||||
ms->tcp_required = 1;
|
||||
ret = NULL;
|
||||
break;
|
||||
case RPZ_DROP_ACTION:
|
||||
@@ -2444,10 +2590,14 @@ struct dns_msg* rpz_callback_from_iterator_cname(struct module_qstate* ms,
|
||||
ms->rpz_passthru = 1;
|
||||
break;
|
||||
default:
|
||||
verbose(VERB_ALGO, "rpz: qname trigger after cname: bug: unhandled or invalid action: '%s'",
|
||||
verbose(VERB_ALGO, "rpz: qname trigger: bug: unhandled or invalid action: '%s'",
|
||||
rpz_action_to_string(localzone_type_to_rpz_action(lzt)));
|
||||
ret = NULL;
|
||||
}
|
||||
if(r->log)
|
||||
log_rpz_apply("qname", (z?z->name:NULL), NULL,
|
||||
localzone_type_to_rpz_action(lzt),
|
||||
&is->qchase, NULL, ms, r->log_name);
|
||||
lock_rw_unlock(&z->lock);
|
||||
lock_rw_unlock(&a->lock);
|
||||
return ret;
|
||||
@@ -2468,8 +2618,21 @@ rpz_apply_maybe_clientip_trigger(struct auth_zones* az, struct module_env* env,
|
||||
az, qinfo, repinfo, taglist, taglen, stats, z_out, a_out, r_out);
|
||||
|
||||
client_action = ((node == NULL) ? RPZ_INVALID_ACTION : node->action);
|
||||
if(node != NULL && *r_out &&
|
||||
(*r_out)->action_override != RPZ_NO_OVERRIDE_ACTION) {
|
||||
client_action = (*r_out)->action_override;
|
||||
}
|
||||
if(client_action == RPZ_PASSTHRU_ACTION) {
|
||||
if(*r_out && (*r_out)->log)
|
||||
log_rpz_apply(
|
||||
(node?"clientip":"qname"),
|
||||
((*z_out)?(*z_out)->name:NULL),
|
||||
(node?&node->node:NULL),
|
||||
client_action, qinfo, repinfo, NULL,
|
||||
(*r_out)->log_name);
|
||||
*passthru = 1;
|
||||
ret = 0;
|
||||
goto done;
|
||||
}
|
||||
if(*z_out == NULL || (client_action != RPZ_INVALID_ACTION &&
|
||||
client_action != RPZ_PASSTHRU_ACTION)) {
|
||||
@@ -2484,14 +2647,15 @@ rpz_apply_maybe_clientip_trigger(struct auth_zones* az, struct module_env* env,
|
||||
if(client_action == RPZ_LOCAL_DATA_ACTION) {
|
||||
rpz_apply_clientip_localdata_action(node, env, qinfo,
|
||||
edns, repinfo, buf, temp, *a_out);
|
||||
ret = 1;
|
||||
} else if(client_action == RPZ_CNAME_OVERRIDE_ACTION) {
|
||||
if(!rpz_apply_cname_override_action(*r_out, qinfo,
|
||||
temp)) {
|
||||
ret = 0;
|
||||
goto done;
|
||||
}
|
||||
ret = 0;
|
||||
} else {
|
||||
if(*r_out && (*r_out)->log)
|
||||
log_rpz_apply(
|
||||
(node?"clientip":"qname"),
|
||||
((*z_out)?(*z_out)->name:NULL),
|
||||
(node?&node->node:NULL),
|
||||
client_action, qinfo, repinfo, NULL,
|
||||
(*r_out)->log_name);
|
||||
local_zones_zone_answer(*z_out /*likely NULL, no zone*/, env, qinfo, edns,
|
||||
repinfo, buf, temp, 0 /* no local data used */,
|
||||
rpz_action_to_localzone_type(client_action));
|
||||
@@ -2499,8 +2663,15 @@ rpz_apply_maybe_clientip_trigger(struct auth_zones* az, struct module_env* env,
|
||||
LDNS_RCODE_WIRE(sldns_buffer_begin(buf))
|
||||
== LDNS_RCODE_NXDOMAIN)
|
||||
LDNS_RA_CLR(sldns_buffer_begin(buf));
|
||||
ret = 1;
|
||||
}
|
||||
ret = 1;
|
||||
if(*r_out && (*r_out)->log)
|
||||
log_rpz_apply(
|
||||
(node?"clientip":"qname"),
|
||||
((*z_out)?(*z_out)->name:NULL),
|
||||
(node?&node->node:NULL),
|
||||
client_action, qinfo, repinfo, NULL,
|
||||
(*r_out)->log_name);
|
||||
goto done;
|
||||
}
|
||||
ret = -1;
|
||||
|
||||
@@ -225,6 +225,14 @@ int rpz_clear(struct rpz* r);
|
||||
*/
|
||||
struct rpz* rpz_create(struct config_auth* p);
|
||||
|
||||
/**
|
||||
* Change config on rpz, after reload.
|
||||
* @param r: the rpz structure.
|
||||
* @param p: the config that was read.
|
||||
* @return false on failure.
|
||||
*/
|
||||
int rpz_config(struct rpz* r, struct config_auth* p);
|
||||
|
||||
/**
|
||||
* String for RPZ action enum
|
||||
* @param a: RPZ action to get string for
|
||||
|
||||
+2
-1
@@ -126,7 +126,8 @@ void view_delete(struct view* v);
|
||||
*/
|
||||
void views_print(struct views* v);
|
||||
|
||||
/* Find a view by name.
|
||||
/**
|
||||
* Find a view by name.
|
||||
* @param vs: views
|
||||
* @param name: name of the view we are looking for
|
||||
* @param write: 1 for obtaining write lock on found view, 0 for read lock
|
||||
|
||||
+3
-3
@@ -106,7 +106,7 @@ ssize_t sldns_bget_token(struct sldns_buffer *b, char *token, const char *delim,
|
||||
* \param[in] k_del keyword delimiter
|
||||
* \param[out] data the data found
|
||||
* \param[in] d_del the data delimiter
|
||||
* \param[in] data_limit maximum size the the data buffer
|
||||
* \param[in] data_limit maximum size the data buffer
|
||||
* \return the number of character read
|
||||
*/
|
||||
ssize_t sldns_fget_keyword_data(FILE *f, const char *keyword, const char *k_del, char *data, const char *d_del, size_t data_limit);
|
||||
@@ -119,7 +119,7 @@ ssize_t sldns_fget_keyword_data(FILE *f, const char *keyword, const char *k_del,
|
||||
* \param[in] k_del keyword delimiter
|
||||
* \param[out] data the data found
|
||||
* \param[in] d_del the data delimiter
|
||||
* \param[in] data_limit maximum size the the data buffer
|
||||
* \param[in] data_limit maximum size the data buffer
|
||||
* \param[in] line_nr pointer to an integer containing the current line number (for
|
||||
debugging purposes)
|
||||
* \return the number of character read
|
||||
@@ -134,7 +134,7 @@ ssize_t sldns_fget_keyword_data_l(FILE *f, const char *keyword, const char *k_de
|
||||
* \param[in] k_del keyword delimiter
|
||||
* \param[out] data the data found
|
||||
* \param[in] d_del the data delimiter
|
||||
* \param[in] data_limit maximum size the the data buffer
|
||||
* \param[in] data_limit maximum size the data buffer
|
||||
* \return the number of character read
|
||||
*/
|
||||
ssize_t sldns_bget_keyword_data(struct sldns_buffer *b, const char *keyword, const char *k_del, char *data, const char *d_del, size_t data_limit);
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user