mirror of
https://github.com/NLnetLabs/unbound.git
synced 2026-08-17 21:25:50 +02:00
Compare commits
555
Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
8ee0bca833 | ||
|
|
c58e6add2b | ||
|
|
93a56205cf | ||
|
|
709f622658 | ||
|
|
307fc6f062 | ||
|
|
8b33c5d7ff | ||
|
|
36bd52afb9 | ||
|
|
b7d13ff12b | ||
|
|
bdfcfb861f | ||
|
|
b444deffd2 | ||
|
|
ff28b7e5cf | ||
|
|
79b84bbc91 | ||
|
|
cbfc3b0342 | ||
|
|
a45da353d3 | ||
|
|
c21e3ee929 | ||
|
|
8a38bed262 | ||
|
|
7cc7a43ff6 | ||
|
|
9bd8df0149 | ||
|
|
8f7411057f | ||
|
|
ca1fe4f82a | ||
|
|
e183c2c506 | ||
|
|
52b18fc6f5 | ||
|
|
e6d00725c2 | ||
|
|
e597711824 | ||
|
|
e1e646c6fc | ||
|
|
fc3b5b4f63 | ||
|
|
1e904a3ce5 | ||
|
|
79e100a7fb | ||
|
|
a65d3d7283 | ||
|
|
3b8766aa43 | ||
|
|
c8b3c89a39 | ||
|
|
a05d460e66 | ||
|
|
5eb362a6c0 | ||
|
|
0735cb28d1 | ||
|
|
737c28e836 | ||
|
|
1bab2dfafa | ||
|
|
22e2c5b6d1 | ||
|
|
914dbfea4e | ||
|
|
cf5e6e89a5 | ||
|
|
4941edf275 | ||
|
|
b08723ef97 | ||
|
|
c163fbc505 | ||
|
|
eed3f1ab38 | ||
|
|
63501f51bb | ||
|
|
1ae2570bda | ||
|
|
9ad825b267 | ||
|
|
3d5e6c0692 | ||
|
|
23e19ca6fc | ||
|
|
9f757aa9f3 | ||
|
|
1df6c170ff | ||
|
|
7a95bedc26 | ||
|
|
ae685bc33d | ||
|
|
91ac449bcd | ||
|
|
c33ad1b1a2 | ||
|
|
84d9682dd0 | ||
|
|
4b1635e194 | ||
|
|
aac261cbb3 | ||
|
|
ae1b3810cc | ||
|
|
96f8755520 | ||
|
|
2ce2ca3691 | ||
|
|
c29ff70f6a | ||
|
|
8a15ffee62 | ||
|
|
8c702de175 | ||
|
|
804cff4c15 | ||
|
|
e180b06298 | ||
|
|
3530c81e29 | ||
|
|
02b16de1ae | ||
|
|
1ad8d4c395 | ||
|
|
364ac737f7 | ||
|
|
f7637a4f18 | ||
|
|
1e1940383a | ||
|
|
f52a9e864b | ||
|
|
13ec8d0f26 | ||
|
|
27f22b8808 | ||
|
|
f54e0791ba | ||
|
|
01dfd2f466 | ||
|
|
f157c691bb | ||
|
|
fea0ff550b | ||
|
|
87d59bfced | ||
|
|
25b2543e5e | ||
|
|
7133e0d32a | ||
|
|
fac7584830 | ||
|
|
87f9258fb4 | ||
|
|
a2fe5356b5 | ||
|
|
ad9b12a863 | ||
|
|
61ca4111a1 | ||
|
|
71a971d70c | ||
|
|
ba4f8478e6 | ||
|
|
374a18cc5b | ||
|
|
f35561287a | ||
|
|
672b9659cf | ||
|
|
1978add0cd | ||
|
|
6cbcea3ac7 | ||
|
|
65e23d4b6f | ||
|
|
fbe41cdef9 | ||
|
|
01a95108b3 | ||
|
|
f75d11821f | ||
|
|
6aa5cfc903 | ||
|
|
f6931c794e | ||
|
|
4c5082ad05 | ||
|
|
5fb892a097 | ||
|
|
55e9532d16 | ||
|
|
fff6657cea | ||
|
|
45d1e75caf | ||
|
|
b806f16c8b | ||
|
|
8d3348c71b | ||
|
|
e2cc14681e | ||
|
|
5ae979bb6e | ||
|
|
8f2fbd66fc | ||
|
|
b5909d8d22 | ||
|
|
fa8e94f155 | ||
|
|
cb5683aeae | ||
|
|
c9715724ec | ||
|
|
78d9cfffd8 | ||
|
|
b47b1d048d | ||
|
|
740952fb82 | ||
|
|
5c550f4548 | ||
|
|
3d78cb8d9a | ||
|
|
1ab75c0043 | ||
|
|
bebc8d516b | ||
|
|
a7debe7ff6 | ||
|
|
215e3920ef | ||
|
|
aabf28aef5 | ||
|
|
aa09835c90 | ||
|
|
9b9e13b665 | ||
|
|
f72e11ef5b | ||
|
|
a45e54555d | ||
|
|
4693c00c9f | ||
|
|
8fe23e0297 | ||
|
|
8557788699 | ||
|
|
81a19ebeb3 | ||
|
|
299df5ec77 | ||
|
|
6f9b6db7be | ||
|
|
96f15b9160 | ||
|
|
159384c2a9 | ||
|
|
621fc91453 | ||
|
|
543c49f76c | ||
|
|
d0a760a587 | ||
|
|
f68cca4097 | ||
|
|
3129357874 | ||
|
|
fc09352df6 | ||
|
|
06da5d45a3 | ||
|
|
69524cadad | ||
|
|
98e95d80e6 | ||
|
|
2f8aa8a43a | ||
|
|
56e60e37ae | ||
|
|
8f5348ab47 | ||
|
|
c5d693b21c | ||
|
|
27e3ac55b9 | ||
|
|
7879218773 | ||
|
|
1354624ba4 | ||
|
|
153f8d5353 | ||
|
|
a1cecf7462 | ||
|
|
e2dac8a00a | ||
|
|
ecd41bef27 | ||
|
|
fd2131687a | ||
|
|
316b9ab4fc | ||
|
|
d45daaf313 | ||
|
|
db1c6d6557 | ||
|
|
e7a713a525 | ||
|
|
39e67508c9 | ||
|
|
3eab974ca2 | ||
|
|
b1d1dcb3b6 | ||
|
|
10cb62aca2 | ||
|
|
6da73aba38 | ||
|
|
1b1b9626ee | ||
|
|
8bc074043a | ||
|
|
04a6322aa4 | ||
|
|
5748f518d1 | ||
|
|
d05eff4d54 | ||
|
|
4544eaa4cc | ||
|
|
5d0770d0ad | ||
|
|
7f4beb846e | ||
|
|
8e8c04e1b9 | ||
|
|
bf0da2ed21 | ||
|
|
670ece06df | ||
|
|
9e41903be8 | ||
|
|
57f92cc97e | ||
|
|
c0741ccc68 | ||
|
|
fb2745024a | ||
|
|
0c15ddd133 | ||
|
|
b53504049c | ||
|
|
a5324e58eb | ||
|
|
963cd68535 | ||
|
|
047df73887 | ||
|
|
d2e1ea7d19 | ||
|
|
fbbe95ba5b | ||
|
|
758c649611 | ||
|
|
a23f95f620 | ||
|
|
5363570df0 | ||
|
|
368857a45b | ||
|
|
40b16d0565 | ||
|
|
08e901a1ac | ||
|
|
bc703c9129 | ||
|
|
9ce52de6c1 | ||
|
|
b3aa262477 | ||
|
|
25e112c674 | ||
|
|
0d2282d551 | ||
|
|
b5f21f4165 | ||
|
|
d357935f66 | ||
|
|
9d2e0f1c02 | ||
|
|
b46ff5c18e | ||
|
|
f597105800 | ||
|
|
3692517a41 | ||
|
|
75b6dba593 | ||
|
|
138fb48eac | ||
|
|
dae7a37974 | ||
|
|
8ae4b4545d | ||
|
|
c343fff3a4 | ||
|
|
a794c87578 | ||
|
|
ef5ca84360 | ||
|
|
8d8fa42266 | ||
|
|
a587535c5d | ||
|
|
94d5babaee | ||
|
|
fe946ba4e9 | ||
|
|
6a31e470f8 | ||
|
|
e577695aeb | ||
|
|
a58bd6cb1e | ||
|
|
4bad944ae4 | ||
|
|
594182f109 | ||
|
|
53c261cb33 | ||
|
|
8703d9a5be | ||
|
|
aa9f1e68ff | ||
|
|
84a4f556b1 | ||
|
|
5b166dbf0a | ||
|
|
9e2233b821 | ||
|
|
13716dc8be | ||
|
|
8ada1bd88d | ||
|
|
9c80bb9fb0 | ||
|
|
33e2863862 | ||
|
|
027e23a11d | ||
|
|
62e8db1c6a | ||
|
|
581b2f31bc | ||
|
|
25fe602024 | ||
|
|
df0e86de49 | ||
|
|
e49b550cf3 | ||
|
|
07c96792f2 | ||
|
|
84ab430e11 | ||
|
|
53499e4a88 | ||
|
|
8a25a97687 | ||
|
|
c112bcf2fd | ||
|
|
9de549c498 | ||
|
|
84c645e7b3 | ||
|
|
197a425c7d | ||
|
|
311054728d | ||
|
|
6d74856212 | ||
|
|
d489e6027e | ||
|
|
e1d146d6b0 | ||
|
|
eb2fe8df8d | ||
|
|
86a8be75f0 | ||
|
|
52fc5ee374 | ||
|
|
82359c8fb1 | ||
|
|
c996671a1f | ||
|
|
e233a1ef65 | ||
|
|
06ff9f20d0 | ||
|
|
af209a12ea | ||
|
|
84ac7e1b58 | ||
|
|
24d502763c | ||
|
|
99c61c19ac | ||
|
|
cb05e9d525 | ||
|
|
abddd4e270 | ||
|
|
656b412492 | ||
|
|
f15a46fcd4 | ||
|
|
8d434bf744 | ||
|
|
13b269d398 | ||
|
|
7aff88881a | ||
|
|
b97bd3a1fc | ||
|
|
6aa5ad85f4 | ||
|
|
42b19c20c1 | ||
|
|
db1fe8b475 | ||
|
|
f4f964f4fb | ||
|
|
a2272860de | ||
|
|
95083d4377 | ||
|
|
5ce0bf5281 | ||
|
|
6a0d5e2cb1 | ||
|
|
330d5211c9 | ||
|
|
2dc28a249a | ||
|
|
c5f14dc880 | ||
|
|
a2ace114de | ||
|
|
2e9b880718 | ||
|
|
a0ec6cd946 | ||
|
|
ea36979c40 | ||
|
|
315077b9e6 | ||
|
|
535d899bef | ||
|
|
8656cfd4c8 | ||
|
|
8f44ddb7de | ||
|
|
4484dc3954 | ||
|
|
eb3bba0724 | ||
|
|
2eff1d8ab5 | ||
|
|
4672fa5b53 | ||
|
|
18029fc44f | ||
|
|
5c6f56f8f1 | ||
|
|
9af29c3ed1 | ||
|
|
76ef8c5803 | ||
|
|
94ef1a8fee | ||
|
|
683241a2f5 | ||
|
|
92ab54641e | ||
|
|
da3812953a | ||
|
|
1bd7c8dfee | ||
|
|
8f96ae7acf | ||
|
|
c4f8e60c85 | ||
|
|
a296b248b0 | ||
|
|
1ef131299a | ||
|
|
5b58a872ef | ||
|
|
94b04d6d46 | ||
|
|
f1a65eb4e8 | ||
|
|
38e1e3eec3 | ||
|
|
bff3d762ff | ||
|
|
fb322f3e87 | ||
|
|
2feee13735 | ||
|
|
1d36696462 | ||
|
|
aa4e2a9e69 | ||
|
|
8e04d04949 | ||
|
|
c5627dbd52 | ||
|
|
014ed9c5ff | ||
|
|
16e1e6d375 | ||
|
|
1a9a4e4ca1 | ||
|
|
f7f638e18f | ||
|
|
c956aea93d | ||
|
|
4556a4f490 | ||
|
|
1cdddf0fe9 | ||
|
|
18fec256b7 | ||
|
|
567c70dada | ||
|
|
8b4b2a88f7 | ||
|
|
faf40c97fc | ||
|
|
daa016e3e4 | ||
|
|
039f69e735 | ||
|
|
b39009e487 | ||
|
|
933769ee73 | ||
|
|
57bff79627 | ||
|
|
1b5559d534 | ||
|
|
9d271c5343 | ||
|
|
74cc49e6c4 | ||
|
|
d414ebf0c7 | ||
|
|
9b123d1b78 | ||
|
|
37b71261a2 | ||
|
|
4426db4d3d | ||
|
|
fe10bc7682 | ||
|
|
67d2eae28c | ||
|
|
9010a7075e | ||
|
|
cc6dbc9f38 | ||
|
|
4198343dbe | ||
|
|
08600d68e8 | ||
|
|
18e098285e | ||
|
|
f1b35bab4b | ||
|
|
84ed77238d | ||
|
|
adb0374a4d | ||
|
|
b0b634558b | ||
|
|
8546247292 | ||
|
|
44659cb3bf | ||
|
|
a1ac2d0252 | ||
|
|
5c7a26b615 | ||
|
|
09d352b917 | ||
|
|
c0522043f0 | ||
|
|
b858801feb | ||
|
|
588db09928 | ||
|
|
5c66c48a1b | ||
|
|
83336477c6 | ||
|
|
e3e5eb66cf | ||
|
|
00d3b97dbb | ||
|
|
f6269baa60 | ||
|
|
19154c6e58 | ||
|
|
0f43b0ea6c | ||
|
|
e6d92f458f | ||
|
|
a31b9d50e2 | ||
|
|
fceb4e8585 | ||
|
|
98f4257890 | ||
|
|
0a15118aff | ||
|
|
e887a79a92 | ||
|
|
f9b9050ab8 | ||
|
|
94735384fd | ||
|
|
5dab0609e5 | ||
|
|
024c921dbf | ||
|
|
1a808e2978 | ||
|
|
56ded934de | ||
|
|
98952f11d1 | ||
|
|
cb4b3de62f | ||
|
|
c8dcfc0853 | ||
|
|
2bb28fdf12 | ||
|
|
6ad26909dd | ||
|
|
9602973c86 | ||
|
|
713b1783d4 | ||
|
|
e06b7eb3f1 | ||
|
|
a33f0638e1 | ||
|
|
bbeee42e25 | ||
|
|
1cb9595a42 | ||
|
|
aa21e38b3a | ||
|
|
964848b94a | ||
|
|
a4dd321fd8 | ||
|
|
d23a28a693 | ||
|
|
5423c0a8e9 | ||
|
|
6a5385f291 | ||
|
|
16f3478048 | ||
|
|
c8860a5fb6 | ||
|
|
735c96aac7 | ||
|
|
a75ea01a15 | ||
|
|
21f02a0865 | ||
|
|
e017d66fc1 | ||
|
|
adaf5dab49 | ||
|
|
feeebc95f8 | ||
|
|
187aa52859 | ||
|
|
f1fea8dc46 | ||
|
|
0c01257d1d | ||
|
|
50a11ebcc8 | ||
|
|
1e2dc657a1 | ||
|
|
843124852f | ||
|
|
5e2fdff8e5 | ||
|
|
499a3a7a61 | ||
|
|
2024c1d050 | ||
|
|
6cd595a816 | ||
|
|
74cf81e9a7 | ||
|
|
35f6fd47fb | ||
|
|
270e099aab | ||
|
|
64645e1401 | ||
|
|
421d317a64 | ||
|
|
0b8ed987de | ||
|
|
9511797487 | ||
|
|
0b7bb75152 | ||
|
|
88c688ec10 | ||
|
|
81fd1dc71c | ||
|
|
69217cf675 | ||
|
|
7c28f1b99c | ||
|
|
fa6340cfa5 | ||
|
|
e471e15774 | ||
|
|
ec3db03121 | ||
|
|
e2bf773089 | ||
|
|
3017a0aa52 | ||
|
|
8419e9780e | ||
|
|
c429c4ab96 | ||
|
|
bc61034f60 | ||
|
|
2dd821c257 | ||
|
|
713b5db537 | ||
|
|
c3a8d5251f | ||
|
|
73e408f1d0 | ||
|
|
d521135f66 | ||
|
|
d71ead5598 | ||
|
|
cdbfadfb7b | ||
|
|
4267de87b5 | ||
|
|
dd6200065f | ||
|
|
a72177e73c | ||
|
|
1d3d78dff5 | ||
|
|
5588f66bdb | ||
|
|
85e916e7e0 | ||
|
|
af96824642 | ||
|
|
8faa95354d | ||
|
|
c57c39833e | ||
|
|
44da5eee66 | ||
|
|
74bc8c9e77 | ||
|
|
0c558cb805 | ||
|
|
533291dce9 | ||
|
|
e613e27f35 | ||
|
|
f2f36a2733 | ||
|
|
78d9bcacb6 | ||
|
|
c170ed1b30 | ||
|
|
ebfa09e04f | ||
|
|
65be1d0ec3 | ||
|
|
ca36e21f71 | ||
|
|
458c793012 | ||
|
|
1341905de8 | ||
|
|
1d877400ea | ||
|
|
8fd4b91afc | ||
|
|
523710f371 | ||
|
|
13bb78a740 | ||
|
|
1e37f86ef5 | ||
|
|
81345fe1e3 | ||
|
|
40877f46e5 | ||
|
|
991108af8d | ||
|
|
4f790bd65e | ||
|
|
d122ae6490 | ||
|
|
651a71fa76 | ||
|
|
2f7890eb6e | ||
|
|
fad747308f | ||
|
|
d55f20fdcc | ||
|
|
19b289feec | ||
|
|
752a3f7f52 | ||
|
|
3ec5d78ac9 | ||
|
|
08d59c9a78 | ||
|
|
cdcc0337d1 | ||
|
|
305adf12bf | ||
|
|
3d7e847a5e | ||
|
|
da6b735ed9 | ||
|
|
5758427d86 | ||
|
|
4f12148af4 | ||
|
|
f8f4779f1f | ||
|
|
da9ab59e10 | ||
|
|
424f86466a | ||
|
|
910288c0d1 | ||
|
|
b6e52c0a52 | ||
|
|
b58af78b63 | ||
|
|
a1150078f2 | ||
|
|
f49e6ccecd | ||
|
|
ad0e0fc290 | ||
|
|
5bf82f2464 | ||
|
|
20f862de51 | ||
|
|
46823f7bc3 | ||
|
|
dd3ac53ff1 | ||
|
|
1a6052fcac | ||
|
|
6689f0b4da | ||
|
|
44ac818f87 | ||
|
|
b4e12030e7 | ||
|
|
9fe92d1119 | ||
|
|
6ba2d6840b | ||
|
|
1de9d6ec66 | ||
|
|
cb919d5126 | ||
|
|
444c839474 | ||
|
|
0276bcbceb | ||
|
|
41c55ffac1 | ||
|
|
4200d23882 | ||
|
|
e2814fe165 | ||
|
|
ca153f4657 | ||
|
|
ee607c0f72 | ||
|
|
2d90d5d729 | ||
|
|
ce72770f61 | ||
|
|
de93a636da | ||
|
|
d3f88d008f | ||
|
|
a1d68cdc96 | ||
|
|
9201c75013 | ||
|
|
f066d6d453 | ||
|
|
a04bd5da29 | ||
|
|
e4cf7aeccf | ||
|
|
a8aa1dbbe1 | ||
|
|
9f29292839 | ||
|
|
1cc1e0b89e | ||
|
|
565bce670c | ||
|
|
c0563f43b0 | ||
|
|
81f3de4da2 | ||
|
|
ff7dfd52a2 | ||
|
|
342a0f48e3 | ||
|
|
71ac59e6f4 | ||
|
|
6662f71732 | ||
|
|
32644937b0 | ||
|
|
1634beb4a0 | ||
|
|
1ef7b4a246 | ||
|
|
03772d10fb | ||
|
|
9152c914af | ||
|
|
a35ac5d82e | ||
|
|
21e3278400 | ||
|
|
8e1deede08 | ||
|
|
4e23523d1a | ||
|
|
8190526250 | ||
|
|
5dd14e2644 | ||
|
|
b50faccb1d | ||
|
|
fcc21885e4 | ||
|
|
a904a3a2c2 | ||
|
|
c253c8367a | ||
|
|
0f95fae445 | ||
|
|
e5bbc36ae0 | ||
|
|
c88fa02c18 | ||
|
|
e794234ac8 | ||
|
|
db53ebb798 | ||
|
|
fe835f9d52 | ||
|
|
9c99b404a1 | ||
|
|
75e8fd7539 | ||
|
|
c88eed83d9 | ||
|
|
50fcf71f04 |
@@ -12,6 +12,7 @@ jobs:
|
||||
build:
|
||||
runs-on: ${{ matrix.os }}
|
||||
strategy:
|
||||
fail-fast: false
|
||||
matrix:
|
||||
include:
|
||||
- name: GCC on Linux
|
||||
@@ -31,12 +32,12 @@ jobs:
|
||||
clang_analysis: "yes"
|
||||
- name: OS X
|
||||
os: macos-latest
|
||||
install_expat: "no"
|
||||
install_expat: "yes"
|
||||
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: "no"
|
||||
install_expat: "yes"
|
||||
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"
|
||||
@@ -48,15 +49,6 @@ jobs:
|
||||
os: ubuntu-latest
|
||||
config: 'CFLAGS="-DNDEBUG -g2 -O3 -fsanitize=address" --disable-flto --disable-static'
|
||||
make_test: "yes"
|
||||
- name: Apple iPhone on iOS, armv7
|
||||
os: macos-latest
|
||||
AUTOTOOLS_HOST: armv7-apple-ios
|
||||
OPENSSL_HOST: ios-cross
|
||||
IOS_SDK: iPhoneOS
|
||||
IOS_CPU: armv7s
|
||||
test_ios: "yes"
|
||||
config: "no"
|
||||
make: "no"
|
||||
- name: Apple iPhone on iOS, arm64
|
||||
os: macos-latest
|
||||
AUTOTOOLS_HOST: aarch64-apple-ios
|
||||
@@ -84,15 +76,6 @@ jobs:
|
||||
test_ios: "yes"
|
||||
config: "no"
|
||||
make: "no"
|
||||
- name: iPhoneSimulator on OS X, i386
|
||||
os: macos-latest
|
||||
AUTOTOOLS_HOST: i386-apple-ios
|
||||
OPENSSL_HOST: iphoneos-cross
|
||||
IOS_SDK: iPhoneSimulator
|
||||
IOS_CPU: i386
|
||||
test_ios: "yes"
|
||||
config: "no"
|
||||
make: "no"
|
||||
- name: iPhoneSimulator on OS X, x86_64
|
||||
os: macos-latest
|
||||
AUTOTOOLS_HOST: x86_64-apple-ios
|
||||
@@ -190,7 +173,7 @@ jobs:
|
||||
cross_platform_config: "--enable-debug --disable-flto --with-libevent --disable-static"
|
||||
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
- uses: actions/checkout@v7
|
||||
with:
|
||||
submodules: false
|
||||
persist-credentials: false
|
||||
@@ -206,6 +189,8 @@ jobs:
|
||||
cd ..
|
||||
export prepath=`pwd`
|
||||
echo prepath=${prepath}
|
||||
# parralel build option
|
||||
export MINJ="-j4"
|
||||
echo "choco install winflexbison3"
|
||||
choco install winflexbison3
|
||||
echo 'LEX="win_flex"'
|
||||
@@ -228,8 +213,8 @@ jobs:
|
||||
C:/msys64/usr/bin/perl ./Configure no-shared no-asm -DOPENSSL_NO_CAPIENG mingw64 --prefix="$prepath/openssl" PERL="C:/msys64/usr/bin/perl"
|
||||
# make the libs only, build faster
|
||||
echo "make build_libs"
|
||||
#make
|
||||
make build_libs
|
||||
#make $MINJ
|
||||
make $MINJ build_libs
|
||||
mv Makefile Makefile.orig
|
||||
# fixup \\ in the installtop to /.
|
||||
echo "fixup INSTALLTOP"
|
||||
@@ -261,7 +246,7 @@ jobs:
|
||||
mv xmlwf/Makefile xmlwf/Makefile.orig
|
||||
sed -e 's/SHELL/SHELLZZ/g' < xmlwf/Makefile.orig > xmlwf/Makefile
|
||||
echo "make"
|
||||
make
|
||||
make $MINJ
|
||||
echo "make install"
|
||||
make install
|
||||
cd ..
|
||||
@@ -269,7 +254,7 @@ jobs:
|
||||
cd unbound
|
||||
echo "./configure --enable-debug --enable-static-exe --disable-flto \"--with-ssl=$prepath/openssl\" --with-libexpat=\"$prepath/expat\" --disable-shared"
|
||||
./configure --enable-debug --enable-static-exe --disable-flto "--with-ssl=$prepath/openssl" --with-libexpat="$prepath/expat" --disable-shared
|
||||
make
|
||||
make $MINJ
|
||||
# specific test output
|
||||
#make testbound.exe; ./testbound.exe -s
|
||||
#make testbound; ./testbound.exe -p testdata/acl.rpl -o -vvvv
|
||||
@@ -364,7 +349,7 @@ jobs:
|
||||
echo "::endgroup::"
|
||||
- name: cross-platform-action on ${{ matrix.cross_platform_os }} ${{ matrix.cross_platform_version }}
|
||||
if: ${{ matrix.with_cross_platform_action == 'yes' }}
|
||||
uses: cross-platform-actions/action@v0.25.0
|
||||
uses: cross-platform-actions/action@v1.0.0
|
||||
env:
|
||||
CROSS_PLATFORM_OS: ${{ matrix.cross_platform_os }}
|
||||
with:
|
||||
|
||||
@@ -12,7 +12,7 @@ jobs:
|
||||
runs-on: ubuntu-latest
|
||||
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
- uses: actions/checkout@v7
|
||||
with:
|
||||
persist-credentials: false
|
||||
- name: configure
|
||||
|
||||
+816
-564
File diff suppressed because it is too large
Load Diff
@@ -4,13 +4,13 @@
|
||||
[](https://repology.org/project/unbound/versions)
|
||||
[](https://bugs.chromium.org/p/oss-fuzz/issues/list?sort=-opened&can=1&q=proj:unbound)
|
||||
[](https://unbound.readthedocs.io/en/latest/?badge=latest)
|
||||
[](https://fosstodon.org/@nlnetlabs)
|
||||
[](https://social.nlnetlabs.nl/@nlnetlabs)
|
||||
|
||||
Unbound is a validating, recursive, caching DNS resolver. It is designed to be
|
||||
fast and lean and incorporates modern features based on open standards. If you
|
||||
have any feedback, we would love to hear from you. Don’t hesitate to
|
||||
[create an issue on Github](https://github.com/NLnetLabs/unbound/issues/new)
|
||||
or post a message on the [Unbound mailing list](https://lists.nlnetlabs.nl/mailman/listinfo/unbound-users).
|
||||
or post a message on our [community forum](https://community.nlnetlabs.nl/).
|
||||
You can learn more about Unbound by reading our
|
||||
[documentation](https://unbound.docs.nlnetlabs.nl/).
|
||||
|
||||
@@ -25,18 +25,21 @@ Unbound can be compiled and installed using:
|
||||
./configure && make && make install
|
||||
```
|
||||
|
||||
You can use libevent if you want. libevent is useful when using many (10000)
|
||||
outgoing ports. By default max 256 ports are opened at the same time and the
|
||||
builtin alternative is equally capable and a little faster.
|
||||
|
||||
You can use libevent if you want. libevent is useful when using many (e.g.,
|
||||
10000) outgoing ports.
|
||||
Use the `--with-libevent` configure option to compile Unbound with libevent
|
||||
support.
|
||||
|
||||
If not, the default builtin alternative opens max 256 ports at the same time
|
||||
and is equally capable and a little faster.
|
||||
|
||||
|
||||
## Unbound configuration
|
||||
|
||||
All of Unbound's configuration options are described in the man pages, which
|
||||
will be installed and are available on the Unbound
|
||||
[documentation page](https://unbound.docs.nlnetlabs.nl/).
|
||||
All of Unbound's configuration options are described in the `unbound.conf(5)`
|
||||
man page, which will be installed and is also available on the Unbound
|
||||
[documentation page](https://unbound.docs.nlnetlabs.nl/en/latest/manpages/unbound.conf.html)
|
||||
for the latest version.
|
||||
|
||||
An example configuration file is located in
|
||||
An example configuration file, with minimal documentation, is located in
|
||||
[doc/example.conf](https://github.com/NLnetLabs/unbound/blob/master/doc/example.conf.in).
|
||||
|
||||
+65
-12
@@ -2,7 +2,12 @@
|
||||
# Copyright 2009, Wouter Wijngaards, NLnet Labs.
|
||||
# BSD licensed.
|
||||
#
|
||||
# Version 48
|
||||
# Version 51
|
||||
# 2025-11-06 Fix ACX_CHECK_NONSTRING_ATTRIBUTE to reject clang, that prints
|
||||
# a warning for 'unknown attribute' when nonstring is used.
|
||||
# 2025-09-29 add ac_cv_func_malloc_0_nonnull as a cache value for the malloc(0)
|
||||
# check by ACX_FUNC_MALLOC.
|
||||
# 2025-09-29 add ACX_CHECK_NONSTRING_ATTRIBUTE, AHX_CONFIG_NONSTRING_ATTRIBUTE.
|
||||
# 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.
|
||||
@@ -71,6 +76,7 @@
|
||||
# ACX_DEPFLAG - find cc dependency flags.
|
||||
# ACX_DETERMINE_EXT_FLAGS_UNBOUND - find out which flags enable BSD and POSIX.
|
||||
# ACX_CHECK_FORMAT_ATTRIBUTE - find cc printf format syntax.
|
||||
# ACX_CHECK_NONSTRING_ATTRIBUTE - find cc nonstring attribute syntax.
|
||||
# ACX_CHECK_UNUSED_ATTRIBUTE - find cc variable unused syntax.
|
||||
# ACX_CHECK_FLTO - see if cc supports -flto and use it if so.
|
||||
# ACX_LIBTOOL_C_ONLY - create libtool for C only, improved.
|
||||
@@ -92,6 +98,7 @@
|
||||
# ACX_FUNC_IOCTLSOCKET - find ioctlsocket, portably.
|
||||
# ACX_FUNC_MALLOC - check malloc, define replacement .
|
||||
# AHX_CONFIG_FORMAT_ATTRIBUTE - config.h text for format.
|
||||
# AHX_CONFIG_NONSTRING_ATTRIBUTE - config.h text for nonstring.
|
||||
# AHX_CONFIG_UNUSED_ATTRIBUTE - config.h text for unused.
|
||||
# AHX_CONFIG_FSEEKO - define fseeko, ftello fallback.
|
||||
# AHX_CONFIG_RAND_MAX - define RAND_MAX if needed.
|
||||
@@ -490,7 +497,7 @@ AC_DEFUN([AHX_CONFIG_FORMAT_ATTRIBUTE],
|
||||
])
|
||||
|
||||
dnl Check how to mark function arguments as unused.
|
||||
dnl result in HAVE_ATTR_UNUSED.
|
||||
dnl result in HAVE_ATTR_UNUSED.
|
||||
dnl Make sure you include AHX_CONFIG_UNUSED_ATTRIBUTE also.
|
||||
AC_DEFUN([ACX_CHECK_UNUSED_ATTRIBUTE],
|
||||
[AC_REQUIRE([AC_PROG_CC])
|
||||
@@ -525,6 +532,49 @@ if test $ac_cv_c_unused_attribute = yes; then
|
||||
fi
|
||||
])dnl
|
||||
|
||||
dnl Check how to mark function arguments as nonstring.
|
||||
dnl result in HAVE_ATTR_NONSTRING.
|
||||
dnl Make sure you include AHX_CONFIG_NONSTRING_ATTRIBUTE also.
|
||||
AC_DEFUN([ACX_CHECK_NONSTRING_ATTRIBUTE],
|
||||
[AC_REQUIRE([AC_PROG_CC])
|
||||
AC_REQUIRE([ACX_CHECK_ERROR_FLAGS])
|
||||
BAKCFLAGS="$CFLAGS"
|
||||
CFLAGS="$CFLAGS $ERRFLAG"
|
||||
AC_MSG_CHECKING(whether the C compiler (${CC-cc}) accepts the "nonstring" attribute)
|
||||
AC_CACHE_VAL(ac_cv_c_nonstring_attribute,
|
||||
[ac_cv_c_nonstring_attribute=no
|
||||
AC_COMPILE_IFELSE([AC_LANG_PROGRAM([[#include <stdio.h>
|
||||
struct test {
|
||||
char __attribute__((nonstring)) s[1];
|
||||
};
|
||||
]], [[
|
||||
struct test t = { "1" };
|
||||
(void) t;
|
||||
]])],[ac_cv_c_nonstring_attribute="yes"],[ac_cv_c_nonstring_attribute="no"])
|
||||
CFLAGS="$BAKCFLAGS"
|
||||
])
|
||||
|
||||
dnl Setup ATTR_NONSTRING config.h parts.
|
||||
dnl make sure you call ACX_CHECK_NONSTRING_ATTRIBUTE also.
|
||||
AC_DEFUN([AHX_CONFIG_NONSTRING_ATTRIBUTE],
|
||||
[
|
||||
#if defined(DOXYGEN)
|
||||
# define ATTR_NONSTRING(x) x
|
||||
#elif defined(__cplusplus)
|
||||
# define ATTR_NONSTRING(x) __attribute__((nonstring)) x
|
||||
#elif defined(HAVE_ATTR_NONSTRING)
|
||||
# define ATTR_NONSTRING(x) __attribute__((nonstring)) x
|
||||
#else /* !HAVE_ATTR_NONSTRING */
|
||||
# define ATTR_NONSTRING(x) x
|
||||
#endif /* !HAVE_ATTR_NONSTRING */
|
||||
])
|
||||
|
||||
AC_MSG_RESULT($ac_cv_c_nonstring_attribute)
|
||||
if test $ac_cv_c_nonstring_attribute = yes; then
|
||||
AC_DEFINE(HAVE_ATTR_NONSTRING, 1, [Whether the C compiler accepts the "nonstring" attribute])
|
||||
fi
|
||||
])dnl
|
||||
|
||||
dnl Pre-fun for ACX_LIBTOOL_C_ONLY
|
||||
AC_DEFUN([ACX_LIBTOOL_C_PRE], [
|
||||
# skip these tests, we do not need them.
|
||||
@@ -1190,8 +1240,9 @@ dnl detect malloc and provide malloc compat prototype.
|
||||
dnl $1: unique name for compat code
|
||||
AC_DEFUN([ACX_FUNC_MALLOC],
|
||||
[
|
||||
AC_MSG_CHECKING([for GNU libc compatible malloc])
|
||||
AC_RUN_IFELSE([AC_LANG_PROGRAM(
|
||||
AC_CACHE_CHECK([for GNU libc compatible malloc],[ac_cv_func_malloc_0_nonnull],
|
||||
[
|
||||
AC_RUN_IFELSE([AC_LANG_PROGRAM(
|
||||
[[#if defined STDC_HEADERS || defined HAVE_STDLIB_H
|
||||
#include <stdlib.h>
|
||||
#else
|
||||
@@ -1199,14 +1250,16 @@ char *malloc ();
|
||||
#endif
|
||||
]], [ if(malloc(0) != 0) return 1;])
|
||||
],
|
||||
[AC_MSG_RESULT([no])
|
||||
AC_LIBOBJ(malloc)
|
||||
AC_DEFINE_UNQUOTED([malloc], [rpl_malloc_$1], [Define if replacement function should be used.])] ,
|
||||
[AC_MSG_RESULT([yes])
|
||||
AC_DEFINE([HAVE_MALLOC], 1, [If have GNU libc compatible malloc])],
|
||||
[AC_MSG_RESULT([no (crosscompile)])
|
||||
AC_LIBOBJ(malloc)
|
||||
AC_DEFINE_UNQUOTED([malloc], [rpl_malloc_$1], [Define if replacement function should be used.])] )
|
||||
[ac_cv_func_malloc_0_nonnull=no],
|
||||
[ac_cv_func_malloc_0_nonnull=yes],
|
||||
[ac_cv_func_malloc_0_nonnull="no (crosscompile)"])
|
||||
])
|
||||
AS_IF([test "$ac_cv_func_malloc_0_nonnull" = yes],
|
||||
[AC_DEFINE([HAVE_MALLOC], 1, [If have GNU libc compatible malloc])],
|
||||
[
|
||||
AC_LIBOBJ(malloc)
|
||||
AC_DEFINE_UNQUOTED([malloc], [rpl_malloc_$1], [Define if replacement function should be used.])
|
||||
])
|
||||
])
|
||||
|
||||
dnl Define fallback for fseeko and ftello if needed.
|
||||
|
||||
+17
-2
@@ -87,7 +87,7 @@
|
||||
# modified version of the Autoconf Macro, you may extend this special
|
||||
# exception to the GPL to apply to your modified version as well.
|
||||
|
||||
#serial 31
|
||||
#serial 32
|
||||
|
||||
AU_ALIAS([ACX_PTHREAD], [AX_PTHREAD])
|
||||
AC_DEFUN([AX_PTHREAD], [
|
||||
@@ -249,7 +249,22 @@ AS_IF([test "x$ax_pthread_clang" = "xyes"],
|
||||
# correctly enabled
|
||||
|
||||
case $host_os in
|
||||
darwin* | hpux* | linux* | osf* | solaris*)
|
||||
solaris*)
|
||||
# Solaris 11.4 introduced XPG7 support and did away with the need for
|
||||
# _REENTRANT.
|
||||
|
||||
AC_EGREP_CPP([AX_PTHREAD_SOLARIS__REENTRANT],
|
||||
[
|
||||
# undef _XOPEN_SOURCE
|
||||
# include <sys/feature_tests.h>
|
||||
# if _XOPEN_VERSION < 700
|
||||
AX_PTHREAD_SOLARIS__REENTRANT
|
||||
# endif
|
||||
],
|
||||
[ax_pthread_check_macro="_REENTRANT"],
|
||||
[ax_pthread_check_macro="--"])
|
||||
;;
|
||||
darwin* | hpux* | linux* | osf*)
|
||||
ax_pthread_check_macro="_REENTRANT"
|
||||
;;
|
||||
|
||||
|
||||
+73
-46
@@ -401,12 +401,15 @@ prep_data(struct module_qstate* qstate, struct sldns_buffer* buf)
|
||||
FLAGS_GET_RCODE(qstate->return_msg->rep->flags) !=
|
||||
LDNS_RCODE_YXDOMAIN)
|
||||
return 0;
|
||||
/* We don't store the reply if its TTL is 0 unless serve-expired is
|
||||
* enabled. Such a reply won't be reusable and simply be a waste for
|
||||
* the backend. It's also compatible with the default behavior of
|
||||
* dns_cache_store_msg(). */
|
||||
if(qstate->return_msg->rep->ttl == 0 &&
|
||||
!qstate->env->cfg->serve_expired)
|
||||
/* Do not persist data the validator has not yet seen, or has rejected.
|
||||
* Otherwise an expired blob could maybe reach clients via
|
||||
* serve-expired. */
|
||||
if(qstate->env->need_to_validate &&
|
||||
qstate->return_msg->rep->security == sec_status_bogus)
|
||||
return 0;
|
||||
/* We don't store the reply if its TTL is 0. This is probably coming
|
||||
* from upstream and it is not meant to be stored. */
|
||||
if(qstate->return_msg->rep->ttl == 0)
|
||||
return 0;
|
||||
|
||||
/* The EDE is added to the out-list so it is encoded in the cached message */
|
||||
@@ -460,7 +463,7 @@ good_expiry_and_qinfo(struct module_qstate* qstate, struct sldns_buffer* buf)
|
||||
* - serve_expired needs to be set
|
||||
* - if SERVE_EXPIRED_TTL is set make sure that the record is not older
|
||||
* than that. */
|
||||
if((time_t)expiry < *qstate->env->now &&
|
||||
if(TTL_IS_EXPIRED((time_t)expiry, *qstate->env->now) &&
|
||||
(!qstate->env->cfg->serve_expired ||
|
||||
(SERVE_EXPIRED_TTL &&
|
||||
*qstate->env->now - (time_t)expiry > SERVE_EXPIRED_TTL)))
|
||||
@@ -472,7 +475,8 @@ good_expiry_and_qinfo(struct module_qstate* qstate, struct sldns_buffer* buf)
|
||||
/* Adjust the TTL of the given RRset by 'subtract'. If 'subtract' is
|
||||
* negative, set the TTL to 0. */
|
||||
static void
|
||||
packed_rrset_ttl_subtract(struct packed_rrset_data* data, time_t subtract)
|
||||
packed_rrset_ttl_subtract(struct packed_rrset_data* data, time_t subtract,
|
||||
time_t timestamp)
|
||||
{
|
||||
size_t i;
|
||||
size_t total = data->count + data->rrsig_count;
|
||||
@@ -484,13 +488,13 @@ packed_rrset_ttl_subtract(struct packed_rrset_data* data, time_t subtract)
|
||||
data->rr_ttl[i] -= subtract;
|
||||
else data->rr_ttl[i] = 0;
|
||||
}
|
||||
data->ttl_add = (subtract < data->ttl_add) ? (data->ttl_add - subtract) : 0;
|
||||
data->ttl_add = timestamp;
|
||||
}
|
||||
|
||||
/* Adjust the TTL of a DNS message and its RRs by 'adjust'. If 'adjust' is
|
||||
* negative, set the TTLs to 0. */
|
||||
static void
|
||||
adjust_msg_ttl(struct dns_msg* msg, time_t adjust)
|
||||
adjust_msg_ttl(struct dns_msg* msg, time_t adjust, time_t timestamp)
|
||||
{
|
||||
size_t i;
|
||||
if(adjust >= 0 && msg->rep->ttl > adjust)
|
||||
@@ -502,13 +506,13 @@ adjust_msg_ttl(struct dns_msg* msg, time_t adjust)
|
||||
|
||||
for(i=0; i<msg->rep->rrset_count; i++) {
|
||||
packed_rrset_ttl_subtract((struct packed_rrset_data*)msg->
|
||||
rep->rrsets[i]->entry.data, adjust);
|
||||
rep->rrsets[i]->entry.data, adjust, timestamp);
|
||||
}
|
||||
}
|
||||
|
||||
/* Set the TTL of the given RRset to fixed value. */
|
||||
static void
|
||||
packed_rrset_ttl_set(struct packed_rrset_data* data, time_t ttl)
|
||||
packed_rrset_ttl_set(struct packed_rrset_data* data, time_t ttl, time_t timestamp)
|
||||
{
|
||||
size_t i;
|
||||
size_t total = data->count + data->rrsig_count;
|
||||
@@ -516,12 +520,12 @@ packed_rrset_ttl_set(struct packed_rrset_data* data, time_t ttl)
|
||||
for(i=0; i<total; i++) {
|
||||
data->rr_ttl[i] = ttl;
|
||||
}
|
||||
data->ttl_add = 0;
|
||||
data->ttl_add = timestamp;
|
||||
}
|
||||
|
||||
/* 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)
|
||||
set_msg_ttl(struct dns_msg* msg, time_t ttl, time_t timestamp)
|
||||
{
|
||||
size_t i;
|
||||
msg->rep->ttl = ttl;
|
||||
@@ -530,14 +534,14 @@ set_msg_ttl(struct dns_msg* msg, time_t 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);
|
||||
rep->rrsets[i]->entry.data, ttl, timestamp);
|
||||
}
|
||||
}
|
||||
|
||||
/** convert dns message in buffer to return_msg */
|
||||
static int
|
||||
parse_data(struct module_qstate* qstate, struct sldns_buffer* buf,
|
||||
int* msg_expired)
|
||||
int* msg_expired, time_t* msg_timestamp, time_t* msg_expiry)
|
||||
{
|
||||
struct msg_parse* prs;
|
||||
struct edns_data edns;
|
||||
@@ -554,6 +558,9 @@ parse_data(struct module_qstate* qstate, struct sldns_buffer* buf,
|
||||
×tamp, sizeof(timestamp));
|
||||
expiry = be64toh(expiry);
|
||||
timestamp = be64toh(timestamp);
|
||||
log_assert(timestamp <= expiry);
|
||||
*msg_expiry = (time_t)expiry;
|
||||
*msg_timestamp = (time_t)timestamp;
|
||||
|
||||
/* parse DNS packet */
|
||||
regional_free_all(qstate->env->scratch);
|
||||
@@ -605,11 +612,9 @@ parse_data(struct module_qstate* qstate, struct sldns_buffer* buf,
|
||||
return 1; /* message from the future (clock skew?) */
|
||||
}
|
||||
adjust = *qstate->env->now - (time_t)timestamp;
|
||||
if(qstate->return_msg->rep->ttl < adjust) {
|
||||
if(TTL_IS_EXPIRED((time_t)expiry, *qstate->env->now)) {
|
||||
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 ||
|
||||
(FLAGS_GET_RCODE(qstate->return_msg->rep->flags)
|
||||
!= LDNS_RCODE_NOERROR &&
|
||||
@@ -618,23 +623,21 @@ parse_data(struct module_qstate* qstate, struct sldns_buffer* buf,
|
||||
FLAGS_GET_RCODE(qstate->return_msg->rep->flags)
|
||||
!= LDNS_RCODE_YXDOMAIN))
|
||||
return 0; /* message expired */
|
||||
else
|
||||
adjust = -1;
|
||||
/* If serve-expired is enabled, we still use an expired message.
|
||||
* Set the TTL to 0 now and it will be handled specially later
|
||||
* when we need to store it internally. */
|
||||
adjust = -1;
|
||||
}
|
||||
adjust_msg_ttl(qstate->return_msg, adjust, timestamp);
|
||||
verbose(VERB_ALGO, "cachedb msg adjusted down by %d", (int)adjust);
|
||||
adjust_msg_ttl(qstate->return_msg, adjust);
|
||||
if(qstate->env->cfg->aggressive_nsec) {
|
||||
limit_nsec_ttl(qstate->return_msg);
|
||||
}
|
||||
|
||||
/* Similar to the unbound worker, if serve-expired is enabled and
|
||||
* the msg would be considered to be expired, mark the state so a
|
||||
* refetch will be scheduled. The comparison between 'expiry' and
|
||||
* '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)) {
|
||||
* refetch will be scheduled. */
|
||||
if(*msg_expired && !qstate->env->cfg->serve_expired_client_timeout) {
|
||||
qstate->need_refetch = 1;
|
||||
}
|
||||
|
||||
@@ -647,7 +650,7 @@ parse_data(struct module_qstate* qstate, struct sldns_buffer* buf,
|
||||
*/
|
||||
static int
|
||||
cachedb_extcache_lookup(struct module_qstate* qstate, struct cachedb_env* ie,
|
||||
int* msg_expired)
|
||||
int* msg_expired, time_t* msg_timestamp, time_t* msg_expiry)
|
||||
{
|
||||
char key[(CACHEDB_HASHSIZE/8)*2+1];
|
||||
calc_hash(&qstate->qinfo, qstate->env, key, sizeof(key));
|
||||
@@ -664,7 +667,8 @@ 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, msg_expired) ) {
|
||||
if( !parse_data(qstate, qstate->env->scratch_buffer, msg_expired,
|
||||
msg_timestamp, msg_expiry) ) {
|
||||
return 0;
|
||||
}
|
||||
return 1;
|
||||
@@ -736,24 +740,30 @@ 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, int msg_expired)
|
||||
cachedb_intcache_store(struct module_qstate* qstate, int msg_expired,
|
||||
time_t msg_timestamp, time_t msg_expiry)
|
||||
{
|
||||
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);
|
||||
time_t original_ttl = msg_expiry - msg_timestamp;
|
||||
store_flags |= DNSCACHE_STORE_EXPIRED_MSG_CACHEDB;
|
||||
/* Pass the original TTL of the expired message and signal with
|
||||
* the DNSCACHE_STORE_EXPIRED_MSG_CACHEDB flag that
|
||||
* dns_cache_store_msg() needs to set absolute expired TTLs
|
||||
* based on the original message TTL.
|
||||
* Results as expired message in the cache */
|
||||
set_msg_ttl(qstate->return_msg, original_ttl, 0);
|
||||
verbose(VERB_ALGO, "cachedb expired msg set to be expired now "
|
||||
"(original ttl: %d)", (int)original_ttl);
|
||||
/* The expired entry does not get checked by the validator
|
||||
* and we need a validation value for it. */
|
||||
/* By setting this to unchecked, bogus data is not returned
|
||||
* as non-bogus. */
|
||||
if(qstate->env->cfg->cachedb_check_when_serve_expired)
|
||||
qstate->return_msg->rep->security = sec_status_insecure;
|
||||
qstate->return_msg->rep->security = sec_status_unchecked;
|
||||
}
|
||||
(void)dns_cache_store(qstate->env, &qstate->qinfo,
|
||||
qstate->return_msg->rep, 0, qstate->prefetch_leeway, 0,
|
||||
@@ -767,12 +777,14 @@ cachedb_intcache_store(struct module_qstate* qstate, int msg_expired)
|
||||
* 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);
|
||||
/* set TTLs as expired for this return_msg in case it is used
|
||||
* later on */
|
||||
set_msg_ttl(qstate->return_msg,
|
||||
EXPIRED_REPLY_TTL_CALC(msg_expiry, msg_timestamp), 0);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -790,6 +802,7 @@ cachedb_handle_query(struct module_qstate* qstate,
|
||||
struct cachedb_env* ie, int id)
|
||||
{
|
||||
int msg_expired = 0;
|
||||
time_t msg_timestamp, msg_expiry;
|
||||
qstate->is_cachedb_answer = 0;
|
||||
/* check if we are enabled, and skip if so */
|
||||
if(!ie->enabled) {
|
||||
@@ -798,8 +811,11 @@ cachedb_handle_query(struct module_qstate* qstate,
|
||||
return;
|
||||
}
|
||||
|
||||
if(qstate->blacklist || qstate->no_cache_lookup) {
|
||||
/* cache is blacklisted or we are instructed from edns to not look */
|
||||
if(qstate->blacklist || qstate->no_cache_lookup
|
||||
|| iter_stub_fwd_no_cache(qstate, &qstate->qinfo, NULL, NULL,
|
||||
NULL, 0)) {
|
||||
/* cache is blacklisted or we are instructed from edns to not
|
||||
* look or a forwarder/stub forbids it */
|
||||
/* pass request to next module */
|
||||
qstate->ext_state[id] = module_wait_module;
|
||||
return;
|
||||
@@ -824,13 +840,15 @@ cachedb_handle_query(struct module_qstate* qstate,
|
||||
}
|
||||
|
||||
/* ask backend cache to see if we have data */
|
||||
if(cachedb_extcache_lookup(qstate, ie, &msg_expired)) {
|
||||
if(cachedb_extcache_lookup(qstate, ie, &msg_expired, &msg_timestamp,
|
||||
&msg_expiry)) {
|
||||
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, msg_expired);
|
||||
cachedb_intcache_store(qstate,
|
||||
msg_expired, msg_timestamp, msg_expiry);
|
||||
/* 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.
|
||||
@@ -850,6 +868,13 @@ cachedb_handle_query(struct module_qstate* qstate,
|
||||
qstate->ext_state[id] = module_wait_module;
|
||||
return;
|
||||
}
|
||||
/* No 0TTL answers escaping from external cache. */
|
||||
if(qstate->return_msg->rep->ttl == 0) {
|
||||
qstate->return_msg = NULL;
|
||||
qstate->ext_state[id] = module_wait_module;
|
||||
return;
|
||||
}
|
||||
log_assert(qstate->return_msg->rep->ttl > 0);
|
||||
qstate->is_cachedb_answer = 1;
|
||||
/* we are done with the query */
|
||||
qstate->ext_state[id] = module_finished;
|
||||
@@ -883,7 +908,9 @@ cachedb_handle_response(struct module_qstate* qstate,
|
||||
{
|
||||
qstate->is_cachedb_answer = 0;
|
||||
/* check if we are not enabled or instructed to not cache, and skip */
|
||||
if(!ie->enabled || qstate->no_cache_store) {
|
||||
if(!ie->enabled || qstate->no_cache_store
|
||||
|| iter_stub_fwd_no_cache(qstate, &qstate->qinfo, NULL, NULL,
|
||||
NULL, 0)) {
|
||||
/* we are done with the query */
|
||||
qstate->ext_state[id] = module_finished;
|
||||
return;
|
||||
|
||||
+136
-14
@@ -46,6 +46,8 @@
|
||||
#include "cachedb/cachedb.h"
|
||||
#include "util/alloc.h"
|
||||
#include "util/config_file.h"
|
||||
#include "util/locks.h"
|
||||
#include "util/timeval_func.h"
|
||||
#include "sldns/sbuffer.h"
|
||||
|
||||
#ifdef USE_REDIS
|
||||
@@ -75,6 +77,18 @@ struct redis_moddata {
|
||||
/* timeout for connection setup */
|
||||
struct timeval connect_timeout;
|
||||
struct timeval replica_connect_timeout;
|
||||
/* the reconnect interval time. */
|
||||
struct timeval reconnect_interval;
|
||||
struct timeval replica_reconnect_interval;
|
||||
/* reconnect attempts, 0 if connected, counts up failed reconnects. */
|
||||
int reconnect_attempts;
|
||||
int replica_reconnect_attempts;
|
||||
/* Lock on reconnect_wait time. */
|
||||
lock_basic_type wait_lock;
|
||||
lock_basic_type replica_wait_lock;
|
||||
/* reconnect wait time, wait until it has passed before reconnect. */
|
||||
struct timeval reconnect_wait;
|
||||
struct timeval replica_reconnect_wait;
|
||||
/* the redis logical database to use */
|
||||
int logical_db;
|
||||
int replica_logical_db;
|
||||
@@ -82,6 +96,10 @@ struct redis_moddata {
|
||||
int set_with_ex_available;
|
||||
};
|
||||
|
||||
/** The limit on the number of redis connect attempts. After failure if
|
||||
* the number is exceeded, the reconnects are throttled by the wait time. */
|
||||
#define REDIS_RECONNECT_ATTEMPT_LIMIT 3
|
||||
|
||||
static redisReply* redis_command(struct module_env*, struct cachedb_env*,
|
||||
const char*, const uint8_t*, size_t, int);
|
||||
|
||||
@@ -105,6 +123,8 @@ moddata_clean(struct redis_moddata** moddata) {
|
||||
}
|
||||
free((*moddata)->replica_ctxs);
|
||||
}
|
||||
lock_basic_destroy(&(*moddata)->wait_lock);
|
||||
lock_basic_destroy(&(*moddata)->replica_wait_lock);
|
||||
free(*moddata);
|
||||
*moddata = NULL;
|
||||
}
|
||||
@@ -113,9 +133,44 @@ static redisContext*
|
||||
redis_connect(const char* host, int port, const char* path,
|
||||
const char* password, int logical_db,
|
||||
const struct timeval connect_timeout,
|
||||
const struct timeval command_timeout)
|
||||
const struct timeval command_timeout,
|
||||
const struct timeval* reconnect_interval,
|
||||
int* reconnect_attempts,
|
||||
struct timeval* reconnect_wait,
|
||||
lock_basic_type* wait_lock,
|
||||
struct timeval* now_tv,
|
||||
const char* infostr)
|
||||
{
|
||||
struct timeval now_val;
|
||||
redisContext* ctx;
|
||||
#ifdef THREADS_DISABLED
|
||||
/* Fix attribute unused warning.
|
||||
* wait_lock is only used with lock_basic_* functions that are nop'ed
|
||||
* when compiled without thread support. */
|
||||
(void)wait_lock;
|
||||
#endif /* THREADS_DISABLED */
|
||||
|
||||
/* See if the redis server is down, and reconnect has to wait. */
|
||||
if(*reconnect_attempts > REDIS_RECONNECT_ATTEMPT_LIMIT) {
|
||||
/* Acquire lock to look at timeval, the integer has atomic
|
||||
* integrity. */
|
||||
struct timeval wait_tv;
|
||||
if(now_tv) {
|
||||
now_val = *now_tv;
|
||||
} else {
|
||||
if(gettimeofday(&now_val, NULL) < 0)
|
||||
log_err("redis: gettimeofday: %s",
|
||||
strerror(errno));
|
||||
}
|
||||
lock_basic_lock(wait_lock);
|
||||
wait_tv = *reconnect_wait;
|
||||
lock_basic_unlock(wait_lock);
|
||||
if(timeval_smaller(&now_val, &wait_tv)) {
|
||||
verbose(VERB_ALGO, "redis %sdown, reconnect wait",
|
||||
infostr);
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
|
||||
if(path && path[0]!=0) {
|
||||
ctx = redisConnectUnixWithTimeout(path, connect_timeout);
|
||||
@@ -126,18 +181,18 @@ redis_connect(const char* host, int port, const char* path,
|
||||
const char *errstr = "out of memory";
|
||||
if(ctx)
|
||||
errstr = ctx->errstr;
|
||||
log_err("failed to connect to redis server: %s", errstr);
|
||||
log_err("failed to connect to redis %sserver: %s", infostr, errstr);
|
||||
goto fail;
|
||||
}
|
||||
if(redisSetTimeout(ctx, command_timeout) != REDIS_OK) {
|
||||
log_err("failed to set redis timeout, %s", ctx->errstr);
|
||||
log_err("failed to set redis %stimeout, %s", infostr, ctx->errstr);
|
||||
goto fail;
|
||||
}
|
||||
if(password && password[0]!=0) {
|
||||
redisReply* rep;
|
||||
rep = redisCommand(ctx, "AUTH %s", password);
|
||||
if(!rep || rep->type == REDIS_REPLY_ERROR) {
|
||||
log_err("failed to authenticate with password");
|
||||
log_err("failed to authenticate %swith password", infostr);
|
||||
freeReplyObject(rep);
|
||||
goto fail;
|
||||
}
|
||||
@@ -147,18 +202,20 @@ redis_connect(const char* host, int port, const char* path,
|
||||
redisReply* rep;
|
||||
rep = redisCommand(ctx, "SELECT %d", logical_db);
|
||||
if(!rep || rep->type == REDIS_REPLY_ERROR) {
|
||||
log_err("failed to set logical database (%d)",
|
||||
logical_db);
|
||||
log_err("failed %sto set logical database (%d)",
|
||||
infostr, logical_db);
|
||||
freeReplyObject(rep);
|
||||
goto fail;
|
||||
}
|
||||
freeReplyObject(rep);
|
||||
}
|
||||
*reconnect_attempts = 0;
|
||||
if(verbosity >= VERB_OPS) {
|
||||
char port_str[6+1];
|
||||
port_str[0] = ' ';
|
||||
(void)snprintf(port_str+1, sizeof(port_str)-1, "%d", port);
|
||||
verbose(VERB_OPS, "Connection to Redis established (%s%s)",
|
||||
verbose(VERB_OPS, "Connection to Redis %sestablished (%s%s)",
|
||||
infostr,
|
||||
path&&path[0]!=0?path:host,
|
||||
path&&path[0]!=0?"":port_str);
|
||||
}
|
||||
@@ -167,6 +224,25 @@ redis_connect(const char* host, int port, const char* path,
|
||||
fail:
|
||||
if(ctx)
|
||||
redisFree(ctx);
|
||||
(*reconnect_attempts)++;
|
||||
if(*reconnect_attempts > REDIS_RECONNECT_ATTEMPT_LIMIT) {
|
||||
/* Wait for the reconnect interval before trying again. */
|
||||
struct timeval tv;
|
||||
if(now_tv) {
|
||||
now_val = *now_tv;
|
||||
} else {
|
||||
if(gettimeofday(&now_val, NULL) < 0)
|
||||
log_err("redis: gettimeofday: %s",
|
||||
strerror(errno));
|
||||
}
|
||||
tv = now_val;
|
||||
timeval_add(&tv, reconnect_interval);
|
||||
lock_basic_lock(wait_lock);
|
||||
*reconnect_wait = tv;
|
||||
lock_basic_unlock(wait_lock);
|
||||
verbose(VERB_ALGO, "redis %sreconnect wait until %d.%6.6d",
|
||||
infostr, (int)tv.tv_sec, (int)tv.tv_usec);
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
@@ -191,6 +267,13 @@ redis_init(struct module_env* env, struct cachedb_env* cachedb_env)
|
||||
log_err("out of memory");
|
||||
goto fail;
|
||||
}
|
||||
lock_basic_init(&moddata->wait_lock);
|
||||
lock_protect(&moddata->wait_lock, &moddata->reconnect_wait,
|
||||
sizeof(moddata->reconnect_wait));
|
||||
lock_basic_init(&moddata->replica_wait_lock);
|
||||
lock_protect(&moddata->replica_wait_lock,
|
||||
&moddata->replica_reconnect_wait,
|
||||
sizeof(moddata->replica_reconnect_wait));
|
||||
moddata->numctxs = env->cfg->num_threads;
|
||||
/* note: server_host and similar string configuration options are
|
||||
* shallow references to configured strings; we don't have to free them
|
||||
@@ -219,6 +302,8 @@ redis_init(struct module_env* env, struct cachedb_env* cachedb_env)
|
||||
set_timeout(&moddata->replica_connect_timeout,
|
||||
env->cfg->redis_replica_timeout,
|
||||
env->cfg->redis_replica_connect_timeout);
|
||||
set_timeout(&moddata->reconnect_interval, 1000, 0);
|
||||
set_timeout(&moddata->replica_reconnect_interval, 1000, 0);
|
||||
|
||||
moddata->logical_db = env->cfg->redis_logical_db;
|
||||
moddata->replica_logical_db = env->cfg->redis_replica_logical_db;
|
||||
@@ -245,7 +330,13 @@ redis_init(struct module_env* env, struct cachedb_env* cachedb_env)
|
||||
moddata->server_password,
|
||||
moddata->logical_db,
|
||||
moddata->connect_timeout,
|
||||
moddata->command_timeout);
|
||||
moddata->command_timeout,
|
||||
&moddata->reconnect_interval,
|
||||
&moddata->reconnect_attempts,
|
||||
&moddata->reconnect_wait,
|
||||
&moddata->wait_lock,
|
||||
env->now_tv,
|
||||
"");
|
||||
if(!ctx) {
|
||||
log_err("redis_init: failed to init redis "
|
||||
"(for thread %d)", i);
|
||||
@@ -263,7 +354,13 @@ redis_init(struct module_env* env, struct cachedb_env* cachedb_env)
|
||||
moddata->replica_server_password,
|
||||
moddata->replica_logical_db,
|
||||
moddata->replica_connect_timeout,
|
||||
moddata->replica_command_timeout);
|
||||
moddata->replica_command_timeout,
|
||||
&moddata->replica_reconnect_interval,
|
||||
&moddata->replica_reconnect_attempts,
|
||||
&moddata->replica_reconnect_wait,
|
||||
&moddata->replica_wait_lock,
|
||||
env->now_tv,
|
||||
"replica ");
|
||||
if(!ctx) {
|
||||
log_err("redis_init: failed to init redis "
|
||||
"replica (for thread %d)", i);
|
||||
@@ -301,7 +398,7 @@ redis_init(struct module_env* env, struct cachedb_env* cachedb_env)
|
||||
set_with_ex_fail:
|
||||
log_err("redis_init: failure during redis_init, the "
|
||||
"redis-expire-records option requires the SET with EX command "
|
||||
"(redis >= 2.6.2)");
|
||||
"(redis >= 2.6.12)");
|
||||
return 1;
|
||||
fail:
|
||||
moddata_clean(&moddata);
|
||||
@@ -364,7 +461,13 @@ redis_command(struct module_env* env, struct cachedb_env* cachedb_env,
|
||||
d->replica_server_password,
|
||||
d->replica_logical_db,
|
||||
d->replica_connect_timeout,
|
||||
d->replica_command_timeout);
|
||||
d->replica_command_timeout,
|
||||
&d->replica_reconnect_interval,
|
||||
&d->replica_reconnect_attempts,
|
||||
&d->replica_reconnect_wait,
|
||||
&d->replica_wait_lock,
|
||||
env->now_tv,
|
||||
"replica ");
|
||||
} else {
|
||||
ctx = redis_connect(
|
||||
d->server_host,
|
||||
@@ -373,7 +476,13 @@ redis_command(struct module_env* env, struct cachedb_env* cachedb_env,
|
||||
d->server_password,
|
||||
d->logical_db,
|
||||
d->connect_timeout,
|
||||
d->command_timeout);
|
||||
d->command_timeout,
|
||||
&d->reconnect_interval,
|
||||
&d->reconnect_attempts,
|
||||
&d->reconnect_wait,
|
||||
&d->wait_lock,
|
||||
env->now_tv,
|
||||
"");
|
||||
}
|
||||
ctx_selector[env->alloc->thread_num] = ctx;
|
||||
}
|
||||
@@ -405,7 +514,14 @@ redis_lookup(struct module_env* env, struct cachedb_env* cachedb_env,
|
||||
char* key, struct sldns_buffer* result_buffer)
|
||||
{
|
||||
redisReply* rep;
|
||||
char cmdbuf[4+(CACHEDB_HASHSIZE/8)*2+1]; /* "GET " + key */
|
||||
/* Supported commands:
|
||||
* - "GET " + key
|
||||
*/
|
||||
#define REDIS_LOOKUP_MAX_BUF_LEN \
|
||||
4 /* "GET " */ \
|
||||
+(CACHEDB_HASHSIZE/8)*2 /* key hash */ \
|
||||
+ 1 /* \0 */
|
||||
char cmdbuf[REDIS_LOOKUP_MAX_BUF_LEN];
|
||||
int n;
|
||||
int ret = 0;
|
||||
|
||||
@@ -465,7 +581,13 @@ redis_store(struct module_env* env, struct cachedb_env* cachedb_env,
|
||||
* older redis 2.0.0 was "SETEX " + key + " " + ttl + " %b"
|
||||
* - "EXPIRE " + key + " 0"
|
||||
*/
|
||||
char cmdbuf[6+(CACHEDB_HASHSIZE/8)*2+11+3+1];
|
||||
#define REDIS_STORE_MAX_BUF_LEN \
|
||||
7 /* "EXPIRE " */ \
|
||||
+(CACHEDB_HASHSIZE/8)*2 /* key hash */ \
|
||||
+ 7 /* " %b EX " */ \
|
||||
+ 20 /* ttl (uint64_t) */ \
|
||||
+ 1 /* \0 */
|
||||
char cmdbuf[REDIS_STORE_MAX_BUF_LEN];
|
||||
|
||||
if (!set_ttl) {
|
||||
verbose(VERB_ALGO, "redis_store %s (%d bytes)", key, (int)data_len);
|
||||
|
||||
@@ -38,6 +38,9 @@
|
||||
#ifndef UB_ON_WINDOWS
|
||||
#include <sys/mman.h>
|
||||
#endif
|
||||
#ifdef __QNX__
|
||||
#include "util/log.h"
|
||||
#endif /* __QNX__ */
|
||||
|
||||
#define KEYSTREAM_ONLY
|
||||
#include "chacha_private.h"
|
||||
@@ -187,7 +190,11 @@ _rs_stir(void)
|
||||
if(errno != ENOSYS ||
|
||||
fallback_getentropy_urandom(rnd, sizeof rnd) == -1) {
|
||||
#ifdef SIGKILL
|
||||
#ifndef __QNX__
|
||||
raise(SIGKILL);
|
||||
#else /* !__QNX__ */
|
||||
fatal_exit("failed to getentropy");
|
||||
#endif /* __QNX__ */
|
||||
#else
|
||||
exit(9); /* windows */
|
||||
#endif
|
||||
|
||||
@@ -48,8 +48,8 @@ typedef struct
|
||||
a = PLUS(a,b); d = ROTATE(XOR(d,a), 8); \
|
||||
c = PLUS(c,d); b = ROTATE(XOR(b,c), 7);
|
||||
|
||||
static const char sigma[16] = "expand 32-byte k";
|
||||
static const char tau[16] = "expand 16-byte k";
|
||||
static const char ATTR_NONSTRING(sigma[16]) = "expand 32-byte k";
|
||||
static const char ATTR_NONSTRING(tau[16]) = "expand 16-byte k";
|
||||
|
||||
static void
|
||||
chacha_keysetup(chacha_ctx *x,const u8 *k,u32 kbits,u32 ATTR_UNUSED(ivbits))
|
||||
|
||||
@@ -57,7 +57,7 @@ int getnameinfo(const struct sockaddr *sa, size_t ATTR_UNUSED(salen), char *host
|
||||
}
|
||||
|
||||
if (host != NULL) {
|
||||
if (flags & NI_NUMERICHOST) {
|
||||
if ((flags & NI_NUMERICHOST)) {
|
||||
if (strlcpy(host, inet_ntoa(sin->sin_addr),
|
||||
hostlen) >= hostlen)
|
||||
return (EAI_MEMORY);
|
||||
@@ -168,7 +168,7 @@ getaddrinfo(const char *hostname, const char *servname,
|
||||
port = 0;
|
||||
}
|
||||
|
||||
if (hints && hints->ai_flags & AI_PASSIVE) {
|
||||
if (hints && (hints->ai_flags & AI_PASSIVE)) {
|
||||
addr = htonl(0x00000000);
|
||||
if (hostname && inet_aton(hostname, &in) != 0)
|
||||
addr = in.s_addr;
|
||||
@@ -193,7 +193,7 @@ getaddrinfo(const char *hostname, const char *servname,
|
||||
}
|
||||
|
||||
/* Don't try DNS if AI_NUMERICHOST is set */
|
||||
if (hints && hints->ai_flags & AI_NUMERICHOST)
|
||||
if (hints && (hints->ai_flags & AI_NUMERICHOST))
|
||||
return (EAI_NONAME);
|
||||
|
||||
hp = gethostbyname(hostname);
|
||||
|
||||
@@ -29,7 +29,9 @@
|
||||
#include <sys/param.h>
|
||||
#include <sys/ioctl.h>
|
||||
#include <sys/resource.h>
|
||||
#ifndef __QNX__
|
||||
#include <sys/syscall.h>
|
||||
#endif /* !__QNX__ */
|
||||
#ifdef SYS__sysctl
|
||||
#include <linux/sysctl.h>
|
||||
#endif
|
||||
@@ -42,7 +44,9 @@
|
||||
#include <stdlib.h>
|
||||
#include <stdint.h>
|
||||
#include <stdio.h>
|
||||
#ifndef __QNX__
|
||||
#include <link.h>
|
||||
#endif /* __QNX__ */
|
||||
#include <termios.h>
|
||||
#include <fcntl.h>
|
||||
#include <signal.h>
|
||||
@@ -60,12 +64,14 @@
|
||||
#define SHA512_Final(r, c) sha512_digest(c, SHA512_DIGEST_SIZE, r)
|
||||
#endif
|
||||
|
||||
#ifndef __QNX__
|
||||
#include <linux/types.h>
|
||||
#include <linux/random.h>
|
||||
#ifdef HAVE_GETAUXVAL
|
||||
#include <sys/auxv.h>
|
||||
#endif
|
||||
#include <sys/vfs.h>
|
||||
#endif /* !__QNX__ */
|
||||
#ifndef MAP_ANON
|
||||
#define MAP_ANON MAP_ANONYMOUS
|
||||
#endif
|
||||
@@ -94,8 +100,10 @@ static int getentropy_urandom(void *buf, size_t len);
|
||||
#ifdef SYS__sysctl
|
||||
static int getentropy_sysctl(void *buf, size_t len);
|
||||
#endif
|
||||
#ifndef __QNX__
|
||||
static int getentropy_fallback(void *buf, size_t len);
|
||||
static int getentropy_phdr(struct dl_phdr_info *info, size_t size, void *data);
|
||||
#endif /* !__QNX__ */
|
||||
|
||||
int
|
||||
getentropy(void *buf, size_t len)
|
||||
@@ -178,6 +186,7 @@ getentropy(void *buf, size_t len)
|
||||
* sysctl ABI, or consider providing a new failsafe API which
|
||||
* works in a chroot or when file descriptors are exhausted.
|
||||
*/
|
||||
#ifndef __QNX__
|
||||
#undef FAIL_INSTEAD_OF_TRYING_FALLBACK
|
||||
#ifdef FAIL_INSTEAD_OF_TRYING_FALLBACK
|
||||
raise(SIGKILL);
|
||||
@@ -185,6 +194,9 @@ getentropy(void *buf, size_t len)
|
||||
ret = getentropy_fallback(buf, len);
|
||||
if (ret != -1)
|
||||
return (ret);
|
||||
#else /* !__QNX__ */
|
||||
fatal_exit("failed to read from /dev/urandom");
|
||||
#endif /* __QNX__ */
|
||||
|
||||
errno = EIO;
|
||||
return (ret);
|
||||
@@ -214,7 +226,11 @@ getentropy_urandom(void *buf, size_t len)
|
||||
{
|
||||
struct stat st;
|
||||
size_t i;
|
||||
#ifndef __QNX__
|
||||
int fd, cnt, flags;
|
||||
#else /* !__QNX__ */
|
||||
int fd, flags;
|
||||
#endif /* __QNX__ */
|
||||
int save_errno = errno;
|
||||
|
||||
start:
|
||||
@@ -241,10 +257,12 @@ start:
|
||||
close(fd);
|
||||
goto nodevrandom;
|
||||
}
|
||||
#ifndef __QNX__
|
||||
if (ioctl(fd, RNDGETENTCNT, &cnt) == -1) {
|
||||
close(fd);
|
||||
goto nodevrandom;
|
||||
}
|
||||
#endif /* !__QNX__ */
|
||||
for (i = 0; i < len; ) {
|
||||
size_t wanted = len - i;
|
||||
ssize_t ret = read(fd, (char *)buf + i, wanted);
|
||||
@@ -265,6 +283,7 @@ nodevrandom:
|
||||
return (-1);
|
||||
}
|
||||
|
||||
#ifndef __QNX__
|
||||
#ifdef SYS__sysctl
|
||||
static int
|
||||
getentropy_sysctl(void *buf, size_t len)
|
||||
@@ -537,3 +556,4 @@ getentropy_fallback(void *buf, size_t len)
|
||||
errno = save_errno;
|
||||
return (0); /* satisfied */
|
||||
}
|
||||
#endif /* !__QNX__ */
|
||||
|
||||
+9
-382
@@ -20,398 +20,25 @@
|
||||
* http://man.openbsd.org/getentropy.2
|
||||
*/
|
||||
|
||||
#include <TargetConditionals.h>
|
||||
#include <sys/types.h>
|
||||
#include <sys/param.h>
|
||||
#include <sys/ioctl.h>
|
||||
#include <sys/resource.h>
|
||||
#include <sys/syscall.h>
|
||||
#include <sys/sysctl.h>
|
||||
#include <sys/statvfs.h>
|
||||
#include <sys/socket.h>
|
||||
#include <sys/mount.h>
|
||||
#include <sys/mman.h>
|
||||
#include <sys/stat.h>
|
||||
#include <sys/time.h>
|
||||
#include <stdlib.h>
|
||||
#include <stdint.h>
|
||||
#include <stdio.h>
|
||||
#include <termios.h>
|
||||
#include <fcntl.h>
|
||||
#include <signal.h>
|
||||
#include <string.h>
|
||||
/* Modified to use SecRandomCopyBytes. It is from macOS 10.7 (2011) and
|
||||
* iOS 2.0 (2008), and is the primary API for cryptographic random numbers. */
|
||||
#include <errno.h>
|
||||
#include <unistd.h>
|
||||
#include <time.h>
|
||||
#include <mach/mach_time.h>
|
||||
#include <mach/mach_host.h>
|
||||
#include <mach/host_info.h>
|
||||
#if TARGET_OS_OSX
|
||||
#include <sys/socketvar.h>
|
||||
#include <sys/vmmeter.h>
|
||||
#endif
|
||||
#include <netinet/in.h>
|
||||
#include <netinet/tcp.h>
|
||||
#if TARGET_OS_OSX
|
||||
#include <netinet/udp.h>
|
||||
#include <netinet/ip_var.h>
|
||||
#include <netinet/tcp_var.h>
|
||||
#include <netinet/udp_var.h>
|
||||
#endif
|
||||
#include <CommonCrypto/CommonDigest.h>
|
||||
#define SHA512_Update(a, b, c) (CC_SHA512_Update((a), (b), (c)))
|
||||
#define SHA512_Init(xxx) (CC_SHA512_Init((xxx)))
|
||||
#define SHA512_Final(xxx, yyy) (CC_SHA512_Final((xxx), (yyy)))
|
||||
#define SHA512_CTX CC_SHA512_CTX
|
||||
#define SHA512_DIGEST_LENGTH CC_SHA512_DIGEST_LENGTH
|
||||
|
||||
#define REPEAT 5
|
||||
#define min(a, b) (((a) < (b)) ? (a) : (b))
|
||||
|
||||
#define HX(a, b) \
|
||||
do { \
|
||||
if ((a)) \
|
||||
HD(errno); \
|
||||
else \
|
||||
HD(b); \
|
||||
} while (0)
|
||||
|
||||
#define HR(x, l) (SHA512_Update(&ctx, (char *)(x), (l)))
|
||||
#define HD(x) (SHA512_Update(&ctx, (char *)&(x), sizeof (x)))
|
||||
#define HF(x) (SHA512_Update(&ctx, (char *)&(x), sizeof (void*)))
|
||||
#include <Security/SecRandom.h>
|
||||
|
||||
int getentropy(void *buf, size_t len);
|
||||
|
||||
static int getentropy_urandom(void *buf, size_t len);
|
||||
static int getentropy_fallback(void *buf, size_t len);
|
||||
|
||||
int
|
||||
getentropy(void *buf, size_t len)
|
||||
{
|
||||
int ret = -1;
|
||||
|
||||
if (len > 256) {
|
||||
errno = EIO;
|
||||
return (-1);
|
||||
goto error;
|
||||
}
|
||||
|
||||
/*
|
||||
* Try to get entropy with /dev/urandom
|
||||
*
|
||||
* This can fail if the process is inside a chroot or if file
|
||||
* descriptors are exhausted.
|
||||
*/
|
||||
ret = getentropy_urandom(buf, len);
|
||||
if (ret != -1)
|
||||
return (ret);
|
||||
|
||||
/*
|
||||
* Entropy collection via /dev/urandom and sysctl have failed.
|
||||
*
|
||||
* No other API exists for collecting entropy, and we have
|
||||
* no failsafe way to get it on OSX that is not sensitive
|
||||
* to resource exhaustion.
|
||||
*
|
||||
* We have very few options:
|
||||
* - Even syslog_r is unsafe to call at this low level, so
|
||||
* there is no way to alert the user or program.
|
||||
* - Cannot call abort() because some systems have unsafe
|
||||
* corefiles.
|
||||
* - Could raise(SIGKILL) resulting in silent program termination.
|
||||
* - Return EIO, to hint that arc4random's stir function
|
||||
* should raise(SIGKILL)
|
||||
* - Do the best under the circumstances....
|
||||
*
|
||||
* This code path exists to bring light to the issue that OSX
|
||||
* does not provide a failsafe API for entropy collection.
|
||||
*
|
||||
* We hope this demonstrates that OSX should consider
|
||||
* providing a new failsafe API which works in a chroot or
|
||||
* when file descriptors are exhausted.
|
||||
*/
|
||||
#undef FAIL_INSTEAD_OF_TRYING_FALLBACK
|
||||
#ifdef FAIL_INSTEAD_OF_TRYING_FALLBACK
|
||||
raise(SIGKILL);
|
||||
#endif
|
||||
ret = getentropy_fallback(buf, len);
|
||||
if (ret != -1)
|
||||
return (ret);
|
||||
if (SecRandomCopyBytes(kSecRandomDefault, len, buf) == errSecSuccess) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
error:
|
||||
errno = EIO;
|
||||
return (ret);
|
||||
}
|
||||
|
||||
static int
|
||||
getentropy_urandom(void *buf, size_t len)
|
||||
{
|
||||
struct stat st;
|
||||
size_t i;
|
||||
int fd, flags;
|
||||
int save_errno = errno;
|
||||
|
||||
start:
|
||||
|
||||
flags = O_RDONLY;
|
||||
#ifdef O_NOFOLLOW
|
||||
flags |= O_NOFOLLOW;
|
||||
#endif
|
||||
#ifdef O_CLOEXEC
|
||||
flags |= O_CLOEXEC;
|
||||
#endif
|
||||
fd = open("/dev/urandom", flags, 0);
|
||||
if (fd == -1) {
|
||||
if (errno == EINTR)
|
||||
goto start;
|
||||
goto nodevrandom;
|
||||
}
|
||||
#ifndef O_CLOEXEC
|
||||
fcntl(fd, F_SETFD, fcntl(fd, F_GETFD) | FD_CLOEXEC);
|
||||
#endif
|
||||
|
||||
/* Lightly verify that the device node looks sane */
|
||||
if (fstat(fd, &st) == -1 || !S_ISCHR(st.st_mode)) {
|
||||
close(fd);
|
||||
goto nodevrandom;
|
||||
}
|
||||
for (i = 0; i < len; ) {
|
||||
size_t wanted = len - i;
|
||||
ssize_t ret = read(fd, (char *)buf + i, wanted);
|
||||
|
||||
if (ret == -1) {
|
||||
if (errno == EAGAIN || errno == EINTR)
|
||||
continue;
|
||||
close(fd);
|
||||
goto nodevrandom;
|
||||
}
|
||||
i += ret;
|
||||
}
|
||||
close(fd);
|
||||
errno = save_errno;
|
||||
return (0); /* satisfied */
|
||||
nodevrandom:
|
||||
errno = EIO;
|
||||
return (-1);
|
||||
}
|
||||
|
||||
#if TARGET_OS_OSX
|
||||
static int tcpmib[] = { CTL_NET, AF_INET, IPPROTO_TCP, TCPCTL_STATS };
|
||||
static int udpmib[] = { CTL_NET, AF_INET, IPPROTO_UDP, UDPCTL_STATS };
|
||||
static int ipmib[] = { CTL_NET, AF_INET, IPPROTO_IP, IPCTL_STATS };
|
||||
#endif
|
||||
static int kmib[] = { CTL_KERN, KERN_USRSTACK };
|
||||
static int hwmib[] = { CTL_HW, HW_USERMEM };
|
||||
|
||||
static int
|
||||
getentropy_fallback(void *buf, size_t len)
|
||||
{
|
||||
uint8_t results[SHA512_DIGEST_LENGTH];
|
||||
int save_errno = errno, e, pgs = getpagesize(), faster = 0, repeat;
|
||||
static int cnt;
|
||||
struct timespec ts;
|
||||
struct timeval tv;
|
||||
struct rusage ru;
|
||||
sigset_t sigset;
|
||||
struct stat st;
|
||||
SHA512_CTX ctx;
|
||||
static pid_t lastpid;
|
||||
pid_t pid;
|
||||
size_t i, ii, m;
|
||||
char *p;
|
||||
#if TARGET_OS_OSX
|
||||
struct tcpstat tcpstat;
|
||||
struct udpstat udpstat;
|
||||
struct ipstat ipstat;
|
||||
#endif
|
||||
u_int64_t mach_time;
|
||||
unsigned int idata;
|
||||
void *addr;
|
||||
|
||||
pid = getpid();
|
||||
if (lastpid == pid) {
|
||||
faster = 1;
|
||||
repeat = 2;
|
||||
} else {
|
||||
faster = 0;
|
||||
lastpid = pid;
|
||||
repeat = REPEAT;
|
||||
}
|
||||
for (i = 0; i < len; ) {
|
||||
int j;
|
||||
SHA512_Init(&ctx);
|
||||
for (j = 0; j < repeat; j++) {
|
||||
HX((e = gettimeofday(&tv, NULL)) == -1, tv);
|
||||
if (e != -1) {
|
||||
cnt += (int)tv.tv_sec;
|
||||
cnt += (int)tv.tv_usec;
|
||||
}
|
||||
|
||||
mach_time = mach_absolute_time();
|
||||
HD(mach_time);
|
||||
|
||||
ii = sizeof(addr);
|
||||
HX(sysctl(kmib, sizeof(kmib) / sizeof(kmib[0]),
|
||||
&addr, &ii, NULL, 0) == -1, addr);
|
||||
|
||||
ii = sizeof(idata);
|
||||
HX(sysctl(hwmib, sizeof(hwmib) / sizeof(hwmib[0]),
|
||||
&idata, &ii, NULL, 0) == -1, idata);
|
||||
|
||||
#if TARGET_OS_OSX
|
||||
ii = sizeof(tcpstat);
|
||||
HX(sysctl(tcpmib, sizeof(tcpmib) / sizeof(tcpmib[0]),
|
||||
&tcpstat, &ii, NULL, 0) == -1, tcpstat);
|
||||
|
||||
ii = sizeof(udpstat);
|
||||
HX(sysctl(udpmib, sizeof(udpmib) / sizeof(udpmib[0]),
|
||||
&udpstat, &ii, NULL, 0) == -1, udpstat);
|
||||
|
||||
ii = sizeof(ipstat);
|
||||
HX(sysctl(ipmib, sizeof(ipmib) / sizeof(ipmib[0]),
|
||||
&ipstat, &ii, NULL, 0) == -1, ipstat);
|
||||
#endif
|
||||
|
||||
HX((pid = getpid()) == -1, pid);
|
||||
HX((pid = getsid(pid)) == -1, pid);
|
||||
HX((pid = getppid()) == -1, pid);
|
||||
HX((pid = getpgid(0)) == -1, pid);
|
||||
HX((e = getpriority(0, 0)) == -1, e);
|
||||
|
||||
if (!faster) {
|
||||
ts.tv_sec = 0;
|
||||
ts.tv_nsec = 1;
|
||||
(void) nanosleep(&ts, NULL);
|
||||
}
|
||||
|
||||
HX(sigpending(&sigset) == -1, sigset);
|
||||
HX(sigprocmask(SIG_BLOCK, NULL, &sigset) == -1,
|
||||
sigset);
|
||||
|
||||
HF(getentropy); /* an addr in this library */
|
||||
HF(printf); /* an addr in libc */
|
||||
p = (char *)&p;
|
||||
HD(p); /* an addr on stack */
|
||||
p = (char *)&errno;
|
||||
HD(p); /* the addr of errno */
|
||||
|
||||
if (i == 0) {
|
||||
struct sockaddr_storage ss;
|
||||
struct statvfs stvfs;
|
||||
struct termios tios;
|
||||
struct statfs stfs;
|
||||
socklen_t ssl;
|
||||
off_t off;
|
||||
|
||||
/*
|
||||
* Prime-sized mappings encourage fragmentation;
|
||||
* thus exposing some address entropy.
|
||||
*/
|
||||
struct mm {
|
||||
size_t npg;
|
||||
void *p;
|
||||
} mm[] = {
|
||||
{ 17, MAP_FAILED }, { 3, MAP_FAILED },
|
||||
{ 11, MAP_FAILED }, { 2, MAP_FAILED },
|
||||
{ 5, MAP_FAILED }, { 3, MAP_FAILED },
|
||||
{ 7, MAP_FAILED }, { 1, MAP_FAILED },
|
||||
{ 57, MAP_FAILED }, { 3, MAP_FAILED },
|
||||
{ 131, MAP_FAILED }, { 1, MAP_FAILED },
|
||||
};
|
||||
|
||||
for (m = 0; m < sizeof mm/sizeof(mm[0]); m++) {
|
||||
HX(mm[m].p = mmap(NULL,
|
||||
mm[m].npg * pgs,
|
||||
PROT_READ|PROT_WRITE,
|
||||
MAP_PRIVATE|MAP_ANON, -1,
|
||||
(off_t)0), mm[m].p);
|
||||
if (mm[m].p != MAP_FAILED) {
|
||||
size_t mo;
|
||||
|
||||
/* Touch some memory... */
|
||||
p = mm[m].p;
|
||||
mo = cnt %
|
||||
(mm[m].npg * pgs - 1);
|
||||
p[mo] = 1;
|
||||
cnt += (int)((long)(mm[m].p)
|
||||
/ pgs);
|
||||
}
|
||||
|
||||
/* Check cnts and times... */
|
||||
mach_time = mach_absolute_time();
|
||||
HD(mach_time);
|
||||
cnt += (int)mach_time;
|
||||
|
||||
HX((e = getrusage(RUSAGE_SELF,
|
||||
&ru)) == -1, ru);
|
||||
if (e != -1) {
|
||||
cnt += (int)ru.ru_utime.tv_sec;
|
||||
cnt += (int)ru.ru_utime.tv_usec;
|
||||
}
|
||||
}
|
||||
|
||||
for (m = 0; m < sizeof mm/sizeof(mm[0]); m++) {
|
||||
if (mm[m].p != MAP_FAILED)
|
||||
munmap(mm[m].p, mm[m].npg * pgs);
|
||||
mm[m].p = MAP_FAILED;
|
||||
}
|
||||
|
||||
HX(stat(".", &st) == -1, st);
|
||||
HX(statvfs(".", &stvfs) == -1, stvfs);
|
||||
HX(statfs(".", &stfs) == -1, stfs);
|
||||
|
||||
HX(stat("/", &st) == -1, st);
|
||||
HX(statvfs("/", &stvfs) == -1, stvfs);
|
||||
HX(statfs("/", &stfs) == -1, stfs);
|
||||
|
||||
HX((e = fstat(0, &st)) == -1, st);
|
||||
if (e == -1) {
|
||||
if (S_ISREG(st.st_mode) ||
|
||||
S_ISFIFO(st.st_mode) ||
|
||||
S_ISSOCK(st.st_mode)) {
|
||||
HX(fstatvfs(0, &stvfs) == -1,
|
||||
stvfs);
|
||||
HX(fstatfs(0, &stfs) == -1,
|
||||
stfs);
|
||||
HX((off = lseek(0, (off_t)0,
|
||||
SEEK_CUR)) < 0, off);
|
||||
}
|
||||
if (S_ISCHR(st.st_mode)) {
|
||||
HX(tcgetattr(0, &tios) == -1,
|
||||
tios);
|
||||
} else if (S_ISSOCK(st.st_mode)) {
|
||||
memset(&ss, 0, sizeof ss);
|
||||
ssl = sizeof(ss);
|
||||
HX(getpeername(0,
|
||||
(void *)&ss, &ssl) == -1,
|
||||
ss);
|
||||
}
|
||||
}
|
||||
|
||||
HX((e = getrusage(RUSAGE_CHILDREN,
|
||||
&ru)) == -1, ru);
|
||||
if (e != -1) {
|
||||
cnt += (int)ru.ru_utime.tv_sec;
|
||||
cnt += (int)ru.ru_utime.tv_usec;
|
||||
}
|
||||
} else {
|
||||
/* Subsequent hashes absorb previous result */
|
||||
HD(results);
|
||||
}
|
||||
|
||||
HX((e = gettimeofday(&tv, NULL)) == -1, tv);
|
||||
if (e != -1) {
|
||||
cnt += (int)tv.tv_sec;
|
||||
cnt += (int)tv.tv_usec;
|
||||
}
|
||||
|
||||
HD(cnt);
|
||||
}
|
||||
|
||||
SHA512_Final(results, &ctx);
|
||||
memcpy((char *)buf + i, results, min(sizeof(results), len - i));
|
||||
i += min(sizeof(results), len - i);
|
||||
}
|
||||
explicit_bzero(&ctx, sizeof ctx);
|
||||
explicit_bzero(results, sizeof results);
|
||||
errno = save_errno;
|
||||
return (0); /* satisfied */
|
||||
return -1;
|
||||
}
|
||||
|
||||
+1
-4
@@ -42,10 +42,7 @@ static const int year_lengths[2] = {
|
||||
};
|
||||
|
||||
static void
|
||||
timesub(timep, offset, tmp)
|
||||
const time_t * const timep;
|
||||
const long offset;
|
||||
struct tm * const tmp;
|
||||
timesub(const time_t * const timep, const long offset, struct tm * const tmp)
|
||||
{
|
||||
long days;
|
||||
long rem;
|
||||
|
||||
+3
-10
@@ -59,10 +59,7 @@ static int inet_pton6 (const char *src, uint8_t *dst);
|
||||
* Paul Vixie, 1996.
|
||||
*/
|
||||
int
|
||||
inet_pton(af, src, dst)
|
||||
int af;
|
||||
const char *src;
|
||||
void *dst;
|
||||
inet_pton(int af, const char *src, void *dst)
|
||||
{
|
||||
switch (af) {
|
||||
case AF_INET:
|
||||
@@ -91,9 +88,7 @@ inet_pton(af, src, dst)
|
||||
* Paul Vixie, 1996.
|
||||
*/
|
||||
static int
|
||||
inet_pton4(src, dst)
|
||||
const char *src;
|
||||
uint8_t *dst;
|
||||
inet_pton4(const char *src, uint8_t *dst)
|
||||
{
|
||||
static const char digits[] = "0123456789";
|
||||
int saw_digit, octets, ch;
|
||||
@@ -145,9 +140,7 @@ inet_pton4(src, dst)
|
||||
* Paul Vixie, 1996.
|
||||
*/
|
||||
static int
|
||||
inet_pton6(src, dst)
|
||||
const char *src;
|
||||
uint8_t *dst;
|
||||
inet_pton6(const char *src, uint8_t *dst)
|
||||
{
|
||||
static const char xdigits_l[] = "0123456789abcdef",
|
||||
xdigits_u[] = "0123456789ABCDEF";
|
||||
|
||||
+80
-3
@@ -31,6 +31,9 @@
|
||||
/* Whether daemon is deprecated */
|
||||
#undef DEPRECATED_DAEMON
|
||||
|
||||
/* Whether X509_NAME_get_text_by_NID is deprecated */
|
||||
#undef DEPRECATED_X509_NAME_GET_TEXT_BY_NID
|
||||
|
||||
/* Deprecate RSA 1024 bit length, makes that an unsupported key */
|
||||
#undef DEPRECATE_RSA_1024
|
||||
|
||||
@@ -60,12 +63,18 @@
|
||||
/* Define to 1 if you have the <arpa/inet.h> header file. */
|
||||
#undef HAVE_ARPA_INET_H
|
||||
|
||||
/* Define to 1 if you have the `ASN1_STRING_get0_data' function. */
|
||||
#undef HAVE_ASN1_STRING_GET0_DATA
|
||||
|
||||
/* Whether the C compiler accepts the "fallthrough" attribute */
|
||||
#undef HAVE_ATTR_FALLTHROUGH
|
||||
|
||||
/* Whether the C compiler accepts the "format" attribute */
|
||||
#undef HAVE_ATTR_FORMAT
|
||||
|
||||
/* Whether the C compiler accepts the "nonstring" attribute */
|
||||
#undef HAVE_ATTR_NONSTRING
|
||||
|
||||
/* Whether the C compiler accepts the "noreturn" attribute */
|
||||
#undef HAVE_ATTR_NORETURN
|
||||
|
||||
@@ -137,6 +146,10 @@
|
||||
to 0 if you don't. */
|
||||
#undef HAVE_DECL_NGTCP2_CRYPTO_ENCRYPT_CB
|
||||
|
||||
/* Define to 1 if you have the declaration of `ngtcp2_crypto_ossl_ctx_new',
|
||||
and to 0 if you don't. */
|
||||
#undef HAVE_DECL_NGTCP2_CRYPTO_OSSL_CTX_NEW
|
||||
|
||||
/* Define to 1 if you have the declaration of `NID_ED25519', and to 0 if you
|
||||
don't. */
|
||||
#undef HAVE_DECL_NID_ED25519
|
||||
@@ -173,6 +186,10 @@
|
||||
0 if you don't. */
|
||||
#undef HAVE_DECL_SSL_CTX_SET_ECDH_AUTO
|
||||
|
||||
/* Define to 1 if you have the declaration of `SSL_CTX_set_tmp_ecdh', and to 0
|
||||
if you don't. */
|
||||
#undef HAVE_DECL_SSL_CTX_SET_TMP_ECDH
|
||||
|
||||
/* Define to 1 if you have the declaration of `strlcat', and to 0 if you
|
||||
don't. */
|
||||
#undef HAVE_DECL_STRLCAT
|
||||
@@ -282,6 +299,12 @@
|
||||
/* Define to 1 if you have the `FIPS_mode' function. */
|
||||
#undef HAVE_FIPS_MODE
|
||||
|
||||
/* Define to 1 if you have the `fnmatch' function. */
|
||||
#undef HAVE_FNMATCH
|
||||
|
||||
/* Define to 1 if you have the <fnmatch.h> header file. */
|
||||
#undef HAVE_FNMATCH_H
|
||||
|
||||
/* Define to 1 if you have the `fork' function. */
|
||||
#undef HAVE_FORK
|
||||
|
||||
@@ -477,6 +500,9 @@
|
||||
`ngtcp2_crypto_quictls_from_ossl_encryption_level' function. */
|
||||
#undef HAVE_NGTCP2_CRYPTO_QUICTLS_FROM_OSSL_ENCRYPTION_LEVEL
|
||||
|
||||
/* Define to 1 if you have the `ngtcp2_crypto_quictls_init' function. */
|
||||
#undef HAVE_NGTCP2_CRYPTO_QUICTLS_INIT
|
||||
|
||||
/* Define to 1 if the system has the type `ngtcp2_encryption_level'. */
|
||||
#undef HAVE_NGTCP2_ENCRYPTION_LEVEL
|
||||
|
||||
@@ -484,6 +510,9 @@
|
||||
*/
|
||||
#undef HAVE_NGTCP2_NGTCP2_CRYPTO_OPENSSL_H
|
||||
|
||||
/* Define to 1 if you have the <ngtcp2/ngtcp2_crypto_ossl.h> header file. */
|
||||
#undef HAVE_NGTCP2_NGTCP2_CRYPTO_OSSL_H
|
||||
|
||||
/* Define to 1 if you have the <ngtcp2/ngtcp2_crypto_quictls.h> header file.
|
||||
*/
|
||||
#undef HAVE_NGTCP2_NGTCP2_CRYPTO_QUICTLS_H
|
||||
@@ -500,6 +529,9 @@
|
||||
/* Define to 1 if you have the <openssl/bn.h> header file. */
|
||||
#undef HAVE_OPENSSL_BN_H
|
||||
|
||||
/* Define to 1 if you have the `OPENSSL_cleanup' function. */
|
||||
#undef HAVE_OPENSSL_CLEANUP
|
||||
|
||||
/* Define to 1 if you have the `OPENSSL_config' function. */
|
||||
#undef HAVE_OPENSSL_CONFIG
|
||||
|
||||
@@ -551,12 +583,27 @@
|
||||
/* Define if you have POSIX threads libraries and header files. */
|
||||
#undef HAVE_PTHREAD
|
||||
|
||||
/* Define to 1 if you have the <pthread_np.h> header file. */
|
||||
#undef HAVE_PTHREAD_NP_H
|
||||
|
||||
/* Have PTHREAD_PRIO_INHERIT. */
|
||||
#undef HAVE_PTHREAD_PRIO_INHERIT
|
||||
|
||||
/* Define to 1 if the system has the type `pthread_rwlock_t'. */
|
||||
#undef HAVE_PTHREAD_RWLOCK_T
|
||||
|
||||
/* Define if pthread_setname_np has the common 2 arguments. */
|
||||
#undef HAVE_PTHREAD_SETNAME_NP
|
||||
|
||||
/* Define if pthread_setname_np has only 1 argument. */
|
||||
#undef HAVE_PTHREAD_SETNAME_NP1
|
||||
|
||||
/* Define if pthread_setname_np has 3 arguments. */
|
||||
#undef HAVE_PTHREAD_SETNAME_NP3
|
||||
|
||||
/* Define if pthread_setname_np exists as pthread_set_name_np instead. */
|
||||
#undef HAVE_PTHREAD_SET_NAME_NP
|
||||
|
||||
/* Define to 1 if the system has the type `pthread_spinlock_t'. */
|
||||
#undef HAVE_PTHREAD_SPINLOCK_T
|
||||
|
||||
@@ -645,9 +692,6 @@
|
||||
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
|
||||
|
||||
@@ -660,9 +704,16 @@
|
||||
/* Define to 1 if you have the `SSL_is_quic' function. */
|
||||
#undef HAVE_SSL_IS_QUIC
|
||||
|
||||
/* Define to 1 if you have the `SSL_set1_dnsname' function. */
|
||||
#undef HAVE_SSL_SET1_DNSNAME
|
||||
|
||||
/* Define to 1 if you have the `SSL_set1_host' function. */
|
||||
#undef HAVE_SSL_SET1_HOST
|
||||
|
||||
/* Define to 1 if you have the `SSL_set_quic_tls_early_data_enabled' function.
|
||||
*/
|
||||
#undef HAVE_SSL_SET_QUIC_TLS_EARLY_DATA_ENABLED
|
||||
|
||||
/* Define to 1 if you have the <stdarg.h> header file. */
|
||||
#undef HAVE_STDARG_H
|
||||
|
||||
@@ -725,6 +776,12 @@
|
||||
/* Define to 1 if `sun_len' is a member of `struct sockaddr_un'. */
|
||||
#undef HAVE_STRUCT_SOCKADDR_UN_SUN_LEN
|
||||
|
||||
/* Define to 1 if `st_mtimensec' is a member of `struct stat'. */
|
||||
#undef HAVE_STRUCT_STAT_ST_MTIMENSEC
|
||||
|
||||
/* Define to 1 if `st_mtim.tv_nsec' is a member of `struct stat'. */
|
||||
#undef HAVE_STRUCT_STAT_ST_MTIM_TV_NSEC
|
||||
|
||||
/* Define if you have Swig libraries and header files. */
|
||||
#undef HAVE_SWIG
|
||||
|
||||
@@ -821,6 +878,12 @@
|
||||
/* Define to 1 if you have the <ws2tcpip.h> header file. */
|
||||
#undef HAVE_WS2TCPIP_H
|
||||
|
||||
/* Define to 1 if you have the `X509_get_key_usage' function. */
|
||||
#undef HAVE_X509_GET_KEY_USAGE
|
||||
|
||||
/* Define to 1 if you have the `X509_NAME_get_text_by_NID' function. */
|
||||
#undef HAVE_X509_NAME_GET_TEXT_BY_NID
|
||||
|
||||
/* Define to 1 if you have the `X509_VERIFY_PARAM_set1_host' function. */
|
||||
#undef HAVE_X509_VERIFY_PARAM_SET1_HOST
|
||||
|
||||
@@ -1023,6 +1086,9 @@
|
||||
/* Define this to enable client TCP Fast Open. */
|
||||
#undef USE_MSG_FASTOPEN
|
||||
|
||||
/* Define this to use ngtcp2_crypto_ossl. */
|
||||
#undef USE_NGTCP2_CRYPTO_OSSL
|
||||
|
||||
/* Define this to enable client TCP Fast Open. */
|
||||
#undef USE_OSX_MSG_FASTOPEN
|
||||
|
||||
@@ -1371,6 +1437,17 @@
|
||||
#endif /* !HAVE_ATTR_UNUSED */
|
||||
|
||||
|
||||
#if defined(DOXYGEN)
|
||||
# define ATTR_NONSTRING(x) x
|
||||
#elif defined(__cplusplus)
|
||||
# define ATTR_NONSTRING(x) __attribute__((nonstring)) x
|
||||
#elif defined(HAVE_ATTR_NONSTRING)
|
||||
# define ATTR_NONSTRING(x) __attribute__((nonstring)) x
|
||||
#else /* !HAVE_ATTR_NONSTRING */
|
||||
# define ATTR_NONSTRING(x) x
|
||||
#endif /* !HAVE_ATTR_NONSTRING */
|
||||
|
||||
|
||||
#ifndef HAVE_FSEEKO
|
||||
#define fseeko fseek
|
||||
#define ftello ftell
|
||||
|
||||
+160
-28
@@ -11,15 +11,15 @@ sinclude(dnscrypt/dnscrypt.m4)
|
||||
|
||||
# must be numbers. ac_defun because of later processing
|
||||
m4_define([VERSION_MAJOR],[1])
|
||||
m4_define([VERSION_MINOR],[23])
|
||||
m4_define([VERSION_MICRO],[0])
|
||||
m4_define([VERSION_MINOR],[26])
|
||||
m4_define([VERSION_MICRO],[1])
|
||||
AC_INIT([unbound],m4_defn([VERSION_MAJOR]).m4_defn([VERSION_MINOR]).m4_defn([VERSION_MICRO]),[unbound-bugs@nlnetlabs.nl or https://github.com/NLnetLabs/unbound/issues],[unbound])
|
||||
AC_SUBST(UNBOUND_VERSION_MAJOR, [VERSION_MAJOR])
|
||||
AC_SUBST(UNBOUND_VERSION_MINOR, [VERSION_MINOR])
|
||||
AC_SUBST(UNBOUND_VERSION_MICRO, [VERSION_MICRO])
|
||||
|
||||
LIBUNBOUND_CURRENT=9
|
||||
LIBUNBOUND_REVISION=31
|
||||
LIBUNBOUND_REVISION=40
|
||||
LIBUNBOUND_AGE=1
|
||||
# 1.0.0 had 0:12:0
|
||||
# 1.0.1 had 0:13:0
|
||||
@@ -118,6 +118,15 @@ LIBUNBOUND_AGE=1
|
||||
# 1.21.1 had 9:29:1
|
||||
# 1.22.0 had 9:30:1
|
||||
# 1.23.0 had 9:31:1
|
||||
# 1.23.1 had 9:32:1
|
||||
# 1.24.0 had 9:33:1
|
||||
# 1.24.1 had 9:34:1
|
||||
# 1.24.2 had 9:35:1
|
||||
# 1.25.0 had 9:36:1
|
||||
# 1.25.1 had 9:37:1
|
||||
# 1.25.2 had 9:38:1
|
||||
# 1.26.0 had 9:39:1
|
||||
# 1.26.1 had 9:40:1
|
||||
|
||||
# Current -- the number of the binary API that we're implementing
|
||||
# Revision -- which iteration of the implementation of the binary
|
||||
@@ -326,6 +335,7 @@ fi
|
||||
AC_C_INLINE
|
||||
ACX_CHECK_FORMAT_ATTRIBUTE
|
||||
ACX_CHECK_UNUSED_ATTRIBUTE
|
||||
ACX_CHECK_NONSTRING_ATTRIBUTE
|
||||
|
||||
AC_DEFUN([CHECK_WEAK_ATTRIBUTE],
|
||||
[AC_REQUIRE([AC_PROG_CC])
|
||||
@@ -356,7 +366,14 @@ AC_MSG_CHECKING(whether the C compiler (${CC-cc}) accepts the "noreturn" attribu
|
||||
AC_CACHE_VAL(ac_cv_c_noreturn_attribute,
|
||||
[ac_cv_c_noreturn_attribute=no
|
||||
AC_COMPILE_IFELSE([AC_LANG_PROGRAM([[ #include <stdio.h>
|
||||
__attribute__((noreturn)) void f(int x) { printf("%d", x); }
|
||||
#ifdef STDC_HEADERS
|
||||
# include <stdlib.h>
|
||||
#else
|
||||
# ifdef HAVE_STDLIB_H
|
||||
# include <stdlib.h>
|
||||
# endif
|
||||
#endif
|
||||
__attribute__((noreturn)) void f(int x) { printf("%d", x); exit(1); }
|
||||
]], [[
|
||||
f(1);
|
||||
]])],[ac_cv_c_noreturn_attribute="yes"],[ac_cv_c_noreturn_attribute="no"])
|
||||
@@ -468,7 +485,7 @@ PKG_PROG_PKG_CONFIG
|
||||
fi
|
||||
|
||||
# Checks for header files.
|
||||
AC_CHECK_HEADERS([stdarg.h stdbool.h netinet/in.h netinet/tcp.h sys/param.h sys/select.h sys/socket.h sys/un.h sys/uio.h sys/resource.h arpa/inet.h syslog.h netdb.h sys/wait.h pwd.h glob.h grp.h login_cap.h winsock2.h ws2tcpip.h endian.h sys/endian.h libkern/OSByteOrder.h sys/ipc.h sys/shm.h ifaddrs.h poll.h],,, [AC_INCLUDES_DEFAULT])
|
||||
AC_CHECK_HEADERS([stdarg.h stdbool.h netinet/in.h netinet/tcp.h sys/param.h sys/select.h sys/socket.h sys/un.h sys/uio.h sys/resource.h arpa/inet.h syslog.h netdb.h sys/wait.h pwd.h glob.h fnmatch.h grp.h login_cap.h winsock2.h ws2tcpip.h endian.h sys/endian.h libkern/OSByteOrder.h sys/ipc.h sys/shm.h ifaddrs.h poll.h],,, [AC_INCLUDES_DEFAULT])
|
||||
# net/if.h portability for Darwin see:
|
||||
# https://www.gnu.org/software/autoconf/manual/autoconf-2.69/html_node/Header-Portability.html
|
||||
AC_CHECK_HEADERS([net/if.h],,, [
|
||||
@@ -631,19 +648,19 @@ AC_ARG_ENABLE(alloc-nonregional, AS_HELP_STRING([--enable-alloc-nonregional],[ e
|
||||
if test x_$enable_alloc_nonregional = x_yes; then
|
||||
AC_DEFINE(UNBOUND_ALLOC_NONREGIONAL, 1, [use malloc not regions, for debug use])
|
||||
fi
|
||||
if test x_$enable_alloc_checks = x_yes; then
|
||||
AS_IF([test x_$enable_alloc_checks = x_yes],[
|
||||
AC_DEFINE(UNBOUND_ALLOC_STATS, 1, [use statistics for allocs and frees, for debug use])
|
||||
SLDNS_ALLOCCHECK_EXTRA_OBJ="alloc.lo log.lo"
|
||||
AC_SUBST(SLDNS_ALLOCCHECK_EXTRA_OBJ)
|
||||
ASYNCLOOK_ALLOCCHECK_EXTRA_OBJ="alloc.lo"
|
||||
AC_SUBST(ASYNCLOOK_ALLOCCHECK_EXTRA_OBJ)
|
||||
else
|
||||
if test x_$enable_alloc_lite = x_yes; then
|
||||
],[
|
||||
AS_IF([test x_$enable_alloc_lite = x_yes],[
|
||||
AC_DEFINE(UNBOUND_ALLOC_LITE, 1, [use to enable lightweight alloc assertions, for debug use])
|
||||
else
|
||||
],[
|
||||
ACX_FUNC_MALLOC([unbound])
|
||||
fi
|
||||
fi
|
||||
])
|
||||
])
|
||||
|
||||
# check windows threads (we use them, not pthreads, on windows).
|
||||
if test "$on_mingw" = "yes"; then
|
||||
@@ -718,6 +735,76 @@ int main(void) {return 0;}
|
||||
])
|
||||
fi
|
||||
|
||||
if test x_$ub_have_pthreads != x_no; then
|
||||
# Long checks to support pthread_setname_np().
|
||||
# Some OSes have the extra non-portable functions in a specific
|
||||
# header file.
|
||||
AC_CHECK_HEADERS([pthread_np.h],,, [AC_INCLUDES_DEFAULT])
|
||||
BAKCFLAGS="$CFLAGS"
|
||||
CFLAGS="$CFLAGS -Werror"
|
||||
# MacOS only has 1 argument, the name.
|
||||
AC_MSG_CHECKING([whether pthread_setname_np has only 1 argument])
|
||||
AC_COMPILE_IFELSE([AC_LANG_PROGRAM([AC_INCLUDES_DEFAULT
|
||||
#include <pthread.h>
|
||||
#ifdef HAVE_PTHREAD_NP_H
|
||||
#include <pthread_np.h>
|
||||
#endif
|
||||
],[
|
||||
(void)pthread_setname_np("");
|
||||
])],[
|
||||
AC_MSG_RESULT(yes)
|
||||
AC_DEFINE(HAVE_PTHREAD_SETNAME_NP1, 1, [Define if pthread_setname_np has only 1 argument.])
|
||||
],[
|
||||
AC_MSG_RESULT(no)
|
||||
])
|
||||
# NetBSD has 3 arguments to allow for formatting of the name.
|
||||
AC_MSG_CHECKING([whether pthread_setname_np has 3 arguments])
|
||||
AC_COMPILE_IFELSE([AC_LANG_PROGRAM([AC_INCLUDES_DEFAULT
|
||||
#include <pthread.h>
|
||||
#ifdef HAVE_PTHREAD_NP_H
|
||||
#include <pthread_np.h>
|
||||
#endif
|
||||
],[
|
||||
(void)pthread_setname_np(0, "", NULL);
|
||||
])],[
|
||||
AC_MSG_RESULT(yes)
|
||||
AC_DEFINE(HAVE_PTHREAD_SETNAME_NP3, 1, [Define if pthread_setname_np has 3 arguments.])
|
||||
],[
|
||||
AC_MSG_RESULT(no)
|
||||
])
|
||||
# Most OSes have the common 2 arguments, thread and name.
|
||||
AC_MSG_CHECKING([whether pthread_setname_np has the common 2 arguments])
|
||||
AC_COMPILE_IFELSE([AC_LANG_PROGRAM([AC_INCLUDES_DEFAULT
|
||||
#include <pthread.h>
|
||||
#ifdef HAVE_PTHREAD_NP_H
|
||||
#include <pthread_np.h>
|
||||
#endif
|
||||
],[
|
||||
(void)pthread_setname_np(0, "");
|
||||
])],[
|
||||
AC_MSG_RESULT(yes)
|
||||
AC_DEFINE(HAVE_PTHREAD_SETNAME_NP, 1, [Define if pthread_setname_np has the common 2 arguments.])
|
||||
],[
|
||||
AC_MSG_RESULT(no)
|
||||
])
|
||||
# FreeBSD/OpenBSD use a slightly different function name.
|
||||
AC_MSG_CHECKING([whether pthread_setname_np exists as pthread_set_name_np instead])
|
||||
AC_COMPILE_IFELSE([AC_LANG_PROGRAM([AC_INCLUDES_DEFAULT
|
||||
#include <pthread.h>
|
||||
#ifdef HAVE_PTHREAD_NP_H
|
||||
#include <pthread_np.h>
|
||||
#endif
|
||||
],[
|
||||
(void)pthread_set_name_np(0, "");
|
||||
])],[
|
||||
AC_MSG_RESULT(yes)
|
||||
AC_DEFINE(HAVE_PTHREAD_SET_NAME_NP, 1, [Define if pthread_setname_np exists as pthread_set_name_np instead.])
|
||||
],[
|
||||
AC_MSG_RESULT(no)
|
||||
])
|
||||
CFLAGS="$BAKCFLAGS"
|
||||
fi
|
||||
|
||||
# check solaris thread library
|
||||
AC_ARG_WITH(solaris-threads, AS_HELP_STRING([--with-solaris-threads],[use solaris native thread library.]), [ ],[ withval="no" ])
|
||||
ub_have_sol_threads=no
|
||||
@@ -995,15 +1082,22 @@ 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 SSL_CTX_set_tmp_ecdh])
|
||||
AC_CHECK_FUNCS([OPENSSL_config EVP_sha1 EVP_sha256 EVP_sha512 FIPS_mode EVP_default_properties_is_fips_enabled EVP_MD_CTX_new OpenSSL_add_all_digests OPENSSL_init_crypto EVP_cleanup ENGINE_cleanup ERR_load_crypto_strings CRYPTO_cleanup_all_ex_data ERR_free_strings RAND_cleanup DSA_SIG_set0 EVP_dss1 EVP_DigestVerify EVP_aes_256_cbc EVP_EncryptInit_ex HMAC_Init_ex CRYPTO_THREADID_set_callback EVP_MAC_CTX_set_params OSSL_PARAM_BLD_new BIO_set_callback_ex OPENSSL_cleanup])
|
||||
|
||||
# these check_funcs need -lssl
|
||||
BAKLIBS="$LIBS"
|
||||
LIBS="-lssl $LIBS"
|
||||
AC_CHECK_FUNCS([OPENSSL_init_ssl SSL_CTX_set_security_level SSL_set1_host SSL_get0_peername X509_VERIFY_PARAM_set1_host SSL_CTX_set_ciphersuites SSL_CTX_set_tlsext_ticket_key_evp_cb SSL_CTX_set_alpn_select_cb SSL_get0_alpn_selected SSL_CTX_set_alpn_protos SSL_get1_peer_certificate])
|
||||
AC_CHECK_FUNCS([OPENSSL_init_ssl SSL_CTX_set_security_level SSL_set1_host SSL_get0_peername SSL_set1_dnsname X509_get_key_usage ASN1_STRING_get0_data X509_VERIFY_PARAM_set1_host SSL_CTX_set_ciphersuites SSL_CTX_set_tlsext_ticket_key_evp_cb SSL_CTX_set_alpn_select_cb SSL_get0_alpn_selected SSL_CTX_set_alpn_protos SSL_get1_peer_certificate])
|
||||
AC_CHECK_FUNCS([X509_NAME_get_text_by_NID])
|
||||
if test $ac_cv_func_X509_NAME_get_text_by_NID = yes; then
|
||||
ACX_FUNC_DEPRECATED([X509_NAME_get_text_by_NID], [
|
||||
(void)X509_NAME_get_text_by_NID(NULL, 0, NULL, 0);], [
|
||||
#include "openssl/x509.h"
|
||||
])
|
||||
fi
|
||||
LIBS="$BAKLIBS"
|
||||
|
||||
AC_CHECK_DECLS([SSL_COMP_get_compression_methods,sk_SSL_COMP_pop_free,SSL_CTX_set_ecdh_auto], [], [], [
|
||||
AC_CHECK_DECLS([SSL_COMP_get_compression_methods,sk_SSL_COMP_pop_free,SSL_CTX_set_ecdh_auto,SSL_CTX_set_tmp_ecdh], [], [], [
|
||||
AC_INCLUDES_DEFAULT
|
||||
#ifdef HAVE_OPENSSL_ERR_H
|
||||
#include <openssl/err.h>
|
||||
@@ -1249,7 +1343,7 @@ case "$enable_ecdsa" in
|
||||
# see if OPENSSL 1.0.0 or later (has EVP MD and Verify independency)
|
||||
AC_MSG_CHECKING([if openssl supports SHA2 and ECDSA with EVP])
|
||||
if grep OPENSSL_VERSION_TEXT $ssldir_include/openssl/opensslv.h | grep "OpenSSL" >/dev/null; then
|
||||
if grep OPENSSL_VERSION_NUMBER $ssldir_include/openssl/opensslv.h | grep 0x0 >/dev/null; then
|
||||
if grep OPENSSL_VERSION_TEXT $ssldir_include/openssl/opensslv.h | grep "OpenSSL 0\." >/dev/null; then
|
||||
AC_MSG_RESULT([no])
|
||||
AC_DEFINE_UNQUOTED([USE_ECDSA_EVP_WORKAROUND], [1], [Define this to enable an EVP workaround for older openssl])
|
||||
else
|
||||
@@ -1609,17 +1703,33 @@ if test x_$withval = x_yes -o x_$withval != x_no; then
|
||||
if test x_$found_libngtcp2 != x_yes; then
|
||||
AC_MSG_ERROR([Could not find libngtcp2, ngtcp2.h])
|
||||
fi
|
||||
AC_CHECK_HEADERS([ngtcp2/ngtcp2.h ngtcp2/ngtcp2_crypto_openssl.h ngtcp2/ngtcp2_crypto_quictls.h],,, [AC_INCLUDES_DEFAULT])
|
||||
AC_CHECK_HEADERS([ngtcp2/ngtcp2.h ngtcp2/ngtcp2_crypto_ossl.h ngtcp2/ngtcp2_crypto_openssl.h ngtcp2/ngtcp2_crypto_quictls.h],,, [AC_INCLUDES_DEFAULT])
|
||||
AC_CHECK_DECLS([ngtcp2_conn_server_new], [], [], [AC_INCLUDES_DEFAULT
|
||||
#include <ngtcp2/ngtcp2.h>
|
||||
])
|
||||
AC_CHECK_DECLS([ngtcp2_crypto_encrypt_cb], [], [], [AC_INCLUDES_DEFAULT
|
||||
#include <ngtcp2/ngtcp2_crypto.h>
|
||||
])
|
||||
AC_CHECK_LIB([ngtcp2_crypto_openssl], [ngtcp2_crypto_encrypt_cb], [ LIBS="$LIBS -lngtcp2_crypto_openssl" ])
|
||||
AC_CHECK_LIB([ngtcp2_crypto_quictls], [ngtcp2_crypto_encrypt_cb], [ LIBS="$LIBS -lngtcp2_crypto_quictls" ])
|
||||
AC_CHECK_FUNCS([ngtcp2_crypto_encrypt_cb ngtcp2_ccerr_default ngtcp2_conn_in_closing_period ngtcp2_conn_in_draining_period ngtcp2_conn_get_max_local_streams_uni ngtcp2_crypto_quictls_from_ossl_encryption_level ngtcp2_crypto_quictls_configure_server_context ngtcp2_crypto_quictls_configure_client_context ngtcp2_conn_get_num_scid ngtcp2_conn_tls_early_data_rejected ngtcp2_conn_encode_0rtt_transport_params])
|
||||
AC_CHECK_LIB([ngtcp2_crypto_ossl], [ngtcp2_crypto_encrypt_cb], [
|
||||
LIBS="$LIBS -lngtcp2_crypto_ossl"
|
||||
AC_DEFINE(USE_NGTCP2_CRYPTO_OSSL, 1, [Define this to use ngtcp2_crypto_ossl.])
|
||||
AC_CHECK_DECLS([ngtcp2_crypto_ossl_ctx_new], [], [AC_MSG_ERROR([No declaration of ngtcp2_crypto_ossl_ctx_new in the ngtcp2_crypto_ossl header file. Perhaps the ngtcp2_crypto_ossl devel header files need to be installed.])], [AC_INCLUDES_DEFAULT
|
||||
#include <ngtcp2/ngtcp2_crypto_ossl.h>
|
||||
])
|
||||
], [
|
||||
AC_CHECK_LIB([ngtcp2_crypto_openssl], [ngtcp2_crypto_encrypt_cb], [ LIBS="$LIBS -lngtcp2_crypto_openssl" ], [
|
||||
AC_CHECK_LIB([ngtcp2_crypto_quictls], [ngtcp2_crypto_encrypt_cb], [ LIBS="$LIBS -lngtcp2_crypto_quictls" ])
|
||||
])
|
||||
])
|
||||
AC_CHECK_FUNCS([ngtcp2_crypto_encrypt_cb ngtcp2_ccerr_default ngtcp2_conn_in_closing_period ngtcp2_conn_in_draining_period ngtcp2_conn_get_max_local_streams_uni ngtcp2_crypto_quictls_from_ossl_encryption_level ngtcp2_crypto_quictls_configure_server_context ngtcp2_crypto_quictls_configure_client_context ngtcp2_crypto_quictls_init ngtcp2_conn_get_num_scid ngtcp2_conn_tls_early_data_rejected ngtcp2_conn_encode_0rtt_transport_params])
|
||||
|
||||
# these check_funcs need -lssl
|
||||
BAKLIBS="$LIBS"
|
||||
LIBS="-lssl $LIBS"
|
||||
AC_CHECK_FUNCS([SSL_is_quic], [], [AC_MSG_ERROR([No QUIC support detected in OpenSSL. Need OpenSSL version with QUIC support to enable DNS over QUIC with libngtcp2.])])
|
||||
AC_CHECK_FUNCS([SSL_set_quic_tls_early_data_enabled])
|
||||
LIBS="$BAKLIBS"
|
||||
|
||||
AC_CHECK_TYPES([struct ngtcp2_version_cid, ngtcp2_encryption_level],,,[AC_INCLUDES_DEFAULT
|
||||
#include <ngtcp2/ngtcp2.h>
|
||||
])
|
||||
@@ -1639,6 +1749,22 @@ if test x_$withval = x_yes -o x_$withval != x_no; then
|
||||
AC_MSG_RESULT(no)
|
||||
])
|
||||
|
||||
AC_CHECK_DECL([CLOCK_MONOTONIC]
|
||||
, []
|
||||
, [AC_MSG_ERROR([ngtcp2 for QUIC needs at least CLOCK_MONOTONIC on the system])]
|
||||
, [AC_INCLUDES_DEFAULT
|
||||
#ifdef TIME_WITH_SYS_TIME
|
||||
# include <sys/time.h>
|
||||
# include <time.h>
|
||||
#else
|
||||
# ifdef HAVE_SYS_TIME_H
|
||||
# include <sys/time.h>
|
||||
# else
|
||||
# include <time.h>
|
||||
# endif
|
||||
#endif
|
||||
])
|
||||
|
||||
fi
|
||||
|
||||
# set static linking for uninstalled libraries if requested
|
||||
@@ -1657,10 +1783,12 @@ if test x_$enable_static_exe = x_yes; then
|
||||
LIBS="$LIBS -lgdi32"
|
||||
fi
|
||||
AC_CHECK_LIB([z], [compress], [ LIBS="$LIBS -lz" ])
|
||||
if echo "$LIBS" | grep -e "libssp.a" -e "lssp" >/dev/null; then
|
||||
:
|
||||
else
|
||||
LIBS="$LIBS -l:libssp.a"
|
||||
if echo "$host" | $GREP -i -e linux >/dev/null; then
|
||||
if echo "$LIBS" | grep -e "libssp.a" -e "lssp" >/dev/null; then
|
||||
:
|
||||
else
|
||||
LIBS="$LIBS -l:libssp.a"
|
||||
fi
|
||||
fi
|
||||
fi
|
||||
fi
|
||||
@@ -1678,10 +1806,12 @@ if test x_$enable_fully_static = x_yes; then
|
||||
LIBS="$LIBS -lgdi32"
|
||||
fi
|
||||
AC_CHECK_LIB([z], [compress], [ LIBS="$LIBS -lz" ])
|
||||
if echo "$LIBS" | grep -e "libssp.a" -e "lssp" >/dev/null; then
|
||||
:
|
||||
else
|
||||
LIBS="$LIBS -l:libssp.a"
|
||||
if echo "$host" | $GREP -i -e linux >/dev/null; then
|
||||
if echo "$LIBS" | grep -e "libssp.a" -e "lssp" >/dev/null; then
|
||||
:
|
||||
else
|
||||
LIBS="$LIBS -l:libssp.a"
|
||||
fi
|
||||
fi
|
||||
fi
|
||||
fi
|
||||
@@ -1740,6 +1870,7 @@ if test $ac_cv_func_daemon = yes; then
|
||||
])
|
||||
fi
|
||||
|
||||
AC_CHECK_MEMBERS([struct stat.st_mtimensec, struct stat.st_mtim.tv_nsec])
|
||||
AC_CHECK_MEMBERS([struct sockaddr_un.sun_len],,,[
|
||||
AC_INCLUDES_DEFAULT
|
||||
#ifdef HAVE_SYS_UN_H
|
||||
@@ -1810,7 +1941,7 @@ AC_LINK_IFELSE([AC_LANG_PROGRAM([
|
||||
AC_MSG_RESULT(no))
|
||||
|
||||
AC_SEARCH_LIBS([setusercontext], [util])
|
||||
AC_CHECK_FUNCS([tzset sigprocmask fcntl getpwnam endpwent getrlimit setrlimit setsid chroot kill chown sleep usleep random srandom recvmsg sendmsg writev socketpair glob initgroups strftime localtime_r setusercontext _beginthreadex endservent endprotoent fsync shmget accept4 getifaddrs if_nametoindex poll gettid])
|
||||
AC_CHECK_FUNCS([tzset sigprocmask fcntl getpwnam endpwent getrlimit setrlimit setsid chroot kill chown sleep usleep random srandom recvmsg sendmsg writev socketpair glob fnmatch initgroups strftime localtime_r setusercontext _beginthreadex endservent endprotoent fsync shmget accept4 getifaddrs if_nametoindex poll gettid])
|
||||
AC_CHECK_FUNCS([setresuid],,[AC_CHECK_FUNCS([setreuid])])
|
||||
AC_CHECK_FUNCS([setresgid],,[AC_CHECK_FUNCS([setregid])])
|
||||
|
||||
@@ -2277,6 +2408,7 @@ dnl includes
|
||||
|
||||
AHX_CONFIG_FORMAT_ATTRIBUTE
|
||||
AHX_CONFIG_UNUSED_ATTRIBUTE
|
||||
AHX_CONFIG_NONSTRING_ATTRIBUTE
|
||||
AHX_CONFIG_FSEEKO
|
||||
AHX_CONFIG_MAXHOSTNAMELEN
|
||||
#if !defined(HAVE_SNPRINTF) || defined(SNPRINTF_RET_BROKEN)
|
||||
|
||||
@@ -58,3 +58,5 @@ distribution but may be helpful.
|
||||
* unbound.init_yocto: An init script to start and stop the server. Put it
|
||||
in /etc/init.d/unbound to use it. It is for the Yocto Project, in
|
||||
embedded systems, contributed by beni-sandu.
|
||||
* gost12.patch: adds ECC-GOST12 support for the informational RFC9558.
|
||||
Contributed by Igor V. Ruzanov.
|
||||
|
||||
@@ -1,10 +1,10 @@
|
||||
diff --git a/doc/unbound.conf.5.in b/doc/unbound.conf.5.in
|
||||
index 5a75e319..c6c6dbe2 100644
|
||||
index 172eb26c..2921c87f 100644
|
||||
--- a/doc/unbound.conf.5.in
|
||||
+++ b/doc/unbound.conf.5.in
|
||||
@@ -970,6 +970,13 @@ potentially broken nameservers. A lot of domains will not be resolvable when
|
||||
this option in enabled. Only use if you know what you are doing.
|
||||
This option only has effect when qname-minimisation is enabled. Default is no.
|
||||
@@ -2146,6 +2146,13 @@ Default: no
|
||||
.UNINDENT
|
||||
.INDENT 0.0
|
||||
.TP
|
||||
+.B aaaa\-filter: \fI<yes or no>
|
||||
+Activate behavior similar to BIND's AAAA-filter.
|
||||
@@ -13,14 +13,14 @@ index 5a75e319..c6c6dbe2 100644
|
||||
+This also causes an additional A query to be sent for each AAAA query.
|
||||
+This breaks DNSSEC!
|
||||
+.TP
|
||||
.B aggressive\-nsec: \fI<yes or no>
|
||||
Aggressive NSEC uses the DNSSEC NSEC chain to synthesize NXDOMAIN
|
||||
and other denials, using information from previous NXDOMAINs answers.
|
||||
.B aggressive\-nsec: \fI<yes or no>\fP
|
||||
Aggressive NSEC uses the DNSSEC NSEC chain to synthesize NXDOMAIN and other
|
||||
denials, using information from previous NXDOMAINs answers.
|
||||
diff --git a/iterator/iter_scrub.c b/iterator/iter_scrub.c
|
||||
index f093c1bf..e55a2246 100644
|
||||
index 49a5f5da..fbe434fa 100644
|
||||
--- a/iterator/iter_scrub.c
|
||||
+++ b/iterator/iter_scrub.c
|
||||
@@ -679,6 +679,32 @@ static int sanitize_nsec_is_overreach(sldns_buffer* pkt,
|
||||
@@ -849,6 +849,32 @@ scrub_sanitize_rr_length(sldns_buffer* pkt, struct msg_parse* msg,
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -53,15 +53,15 @@ index f093c1bf..e55a2246 100644
|
||||
/**
|
||||
* Given a response event, remove suspect RRsets from the response.
|
||||
* "Suspect" rrsets are potentially poison. Note that this routine expects
|
||||
@@ -698,6 +724,7 @@ scrub_sanitize(sldns_buffer* pkt, struct msg_parse* msg,
|
||||
@@ -869,6 +895,7 @@ 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 found_a_record = 0; /* ASN: do we have a A record? */
|
||||
int del_addi = 0; /* if additional-holding rrsets are deleted, we
|
||||
do not trust the normalized additional-A-AAAA any more */
|
||||
struct rrset_parse* rrset, *prev;
|
||||
@@ -733,6 +760,13 @@ scrub_sanitize(sldns_buffer* pkt, struct msg_parse* msg,
|
||||
uint8_t* ns_rrset_dname = NULL;
|
||||
@@ -906,6 +933,13 @@ scrub_sanitize(sldns_buffer* pkt, struct msg_parse* msg,
|
||||
rrset = rrset->rrset_all_next;
|
||||
}
|
||||
|
||||
@@ -75,9 +75,9 @@ index f093c1bf..e55a2246 100644
|
||||
/* At this point, we brutally remove ALL rrsets that aren't
|
||||
* children of the originating zone. The idea here is that,
|
||||
* as far as we know, the server that we contacted is ONLY
|
||||
@@ -744,6 +778,24 @@ scrub_sanitize(sldns_buffer* pkt, struct msg_parse* msg,
|
||||
rrset = msg->rrset_first;
|
||||
while(rrset) {
|
||||
@@ -925,6 +959,24 @@ scrub_sanitize(sldns_buffer* pkt, struct msg_parse* msg,
|
||||
continue;
|
||||
}
|
||||
|
||||
+ /* ASN: For AAAA records only... */
|
||||
+ if((ie->aaaa_filter) && (rrset->type == LDNS_RR_TYPE_AAAA)) {
|
||||
@@ -101,10 +101,10 @@ index f093c1bf..e55a2246 100644
|
||||
if( (rrset->type == LDNS_RR_TYPE_A ||
|
||||
rrset->type == LDNS_RR_TYPE_AAAA)) {
|
||||
diff --git a/iterator/iter_utils.c b/iterator/iter_utils.c
|
||||
index 2482a1f4..bd5ba243 100644
|
||||
index 1da21896..6583dd0e 100644
|
||||
--- a/iterator/iter_utils.c
|
||||
+++ b/iterator/iter_utils.c
|
||||
@@ -177,6 +177,7 @@ iter_apply_cfg(struct iter_env* iter_env, struct config_file* cfg)
|
||||
@@ -250,6 +250,7 @@ iter_apply_cfg(struct iter_env* iter_env, struct config_file* cfg)
|
||||
iter_env->outbound_msg_retry = cfg->outbound_msg_retry;
|
||||
iter_env->max_sent_count = cfg->max_sent_count;
|
||||
iter_env->max_query_restarts = cfg->max_query_restarts;
|
||||
@@ -113,12 +113,12 @@ index 2482a1f4..bd5ba243 100644
|
||||
}
|
||||
|
||||
diff --git a/iterator/iterator.c b/iterator/iterator.c
|
||||
index 54006940..768fe202 100644
|
||||
index 71e64655..735f4ca0 100644
|
||||
--- a/iterator/iterator.c
|
||||
+++ b/iterator/iterator.c
|
||||
@@ -2155,6 +2155,53 @@ processDSNSFind(struct module_qstate* qstate, struct iter_qstate* iq, int id)
|
||||
|
||||
return 0;
|
||||
@@ -2412,6 +2412,53 @@ check_waiting_queries(struct iter_qstate* iq, struct module_qstate* qstate,
|
||||
qstate->ext_state[id] = module_wait_reply;
|
||||
}
|
||||
}
|
||||
+
|
||||
+/**
|
||||
@@ -170,8 +170,8 @@ index 54006940..768fe202 100644
|
||||
|
||||
/**
|
||||
* This is the request event state where the request will be sent to one of
|
||||
@@ -2216,6 +2263,13 @@ processQueryTargets(struct module_qstate* qstate, struct iter_qstate* iq,
|
||||
return error_response(qstate, id, LDNS_RCODE_SERVFAIL);
|
||||
@@ -2554,6 +2601,13 @@ processQueryTargets(struct module_qstate* qstate, struct iter_qstate* iq,
|
||||
}
|
||||
}
|
||||
|
||||
+ /* ASN: If we have a AAAA query, then also query for A records */
|
||||
@@ -184,7 +184,7 @@ index 54006940..768fe202 100644
|
||||
/* Make sure we have a delegation point, otherwise priming failed
|
||||
* or another failure occurred */
|
||||
if(!iq->dp) {
|
||||
@@ -3648,6 +3702,61 @@ processFinished(struct module_qstate* qstate, struct iter_qstate* iq,
|
||||
@@ -4178,6 +4232,61 @@ processFinished(struct module_qstate* qstate, struct iter_qstate* iq,
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -246,7 +246,7 @@ index 54006940..768fe202 100644
|
||||
/*
|
||||
* Return priming query results to interested super querystates.
|
||||
*
|
||||
@@ -3667,6 +3776,9 @@ iter_inform_super(struct module_qstate* qstate, int id,
|
||||
@@ -4197,6 +4306,9 @@ iter_inform_super(struct module_qstate* qstate, int id,
|
||||
else if(super->qinfo.qtype == LDNS_RR_TYPE_DS && ((struct iter_qstate*)
|
||||
super->minfo[id])->state == DSNS_FIND_STATE)
|
||||
processDSNSResponse(qstate, id, super);
|
||||
@@ -256,7 +256,7 @@ index 54006940..768fe202 100644
|
||||
else if(qstate->return_rcode != LDNS_RCODE_NOERROR)
|
||||
error_supers(qstate, id, super);
|
||||
else if(qstate->is_priming)
|
||||
@@ -3704,6 +3816,9 @@ iter_handle(struct module_qstate* qstate, struct iter_qstate* iq,
|
||||
@@ -4234,6 +4346,9 @@ iter_handle(struct module_qstate* qstate, struct iter_qstate* iq,
|
||||
case INIT_REQUEST_3_STATE:
|
||||
cont = processInitRequest3(qstate, iq, id);
|
||||
break;
|
||||
@@ -266,7 +266,7 @@ index 54006940..768fe202 100644
|
||||
case QUERYTARGETS_STATE:
|
||||
cont = processQueryTargets(qstate, iq, ie, id);
|
||||
break;
|
||||
@@ -4040,6 +4155,8 @@ iter_state_to_string(enum iter_state state)
|
||||
@@ -4578,6 +4693,8 @@ iter_state_to_string(enum iter_state state)
|
||||
return "INIT REQUEST STATE (stage 2)";
|
||||
case INIT_REQUEST_3_STATE:
|
||||
return "INIT REQUEST STATE (stage 3)";
|
||||
@@ -275,7 +275,7 @@ index 54006940..768fe202 100644
|
||||
case QUERYTARGETS_STATE :
|
||||
return "QUERY TARGETS STATE";
|
||||
case PRIME_RESP_STATE :
|
||||
@@ -4064,6 +4181,7 @@ iter_state_is_responsestate(enum iter_state s)
|
||||
@@ -4602,6 +4719,7 @@ iter_state_is_responsestate(enum iter_state s)
|
||||
case INIT_REQUEST_STATE :
|
||||
case INIT_REQUEST_2_STATE :
|
||||
case INIT_REQUEST_3_STATE :
|
||||
@@ -284,10 +284,10 @@ index 54006940..768fe202 100644
|
||||
case COLLECT_CLASS_STATE :
|
||||
return 0;
|
||||
diff --git a/iterator/iterator.h b/iterator/iterator.h
|
||||
index 8b840528..a61c4195 100644
|
||||
index ae4b4e45..a44f9d27 100644
|
||||
--- a/iterator/iterator.h
|
||||
+++ b/iterator/iterator.h
|
||||
@@ -133,6 +133,9 @@ struct iter_env {
|
||||
@@ -157,6 +157,9 @@ struct iter_env {
|
||||
*/
|
||||
int* target_fetch_policy;
|
||||
|
||||
@@ -297,7 +297,7 @@ index 8b840528..a61c4195 100644
|
||||
/** lock on ratelimit counter */
|
||||
lock_basic_type queries_ratelimit_lock;
|
||||
/** number of queries that have been ratelimited */
|
||||
@@ -187,6 +190,14 @@ enum iter_state {
|
||||
@@ -217,6 +220,14 @@ enum iter_state {
|
||||
*/
|
||||
INIT_REQUEST_3_STATE,
|
||||
|
||||
@@ -312,9 +312,9 @@ index 8b840528..a61c4195 100644
|
||||
/**
|
||||
* Each time a delegation point changes for a given query or a
|
||||
* query times out and/or wakes up, this state is (re)visited.
|
||||
@@ -376,6 +387,13 @@ struct iter_qstate {
|
||||
*/
|
||||
int refetch_glue;
|
||||
@@ -434,6 +445,13 @@ struct iter_qstate {
|
||||
* already so that it is accepted later. */
|
||||
int empty_nodata_found;
|
||||
|
||||
+ /**
|
||||
+ * ASN: This is a flag that, if true, means that this query is
|
||||
@@ -327,10 +327,10 @@ index 8b840528..a61c4195 100644
|
||||
struct outbound_list outlist;
|
||||
|
||||
diff --git a/pythonmod/interface.i b/pythonmod/interface.i
|
||||
index 1ca8686a..d91b19ec 100644
|
||||
index 2040fb9e..f073c3dc 100644
|
||||
--- a/pythonmod/interface.i
|
||||
+++ b/pythonmod/interface.i
|
||||
@@ -995,6 +995,7 @@ struct config_file {
|
||||
@@ -1013,6 +1013,7 @@ struct config_file {
|
||||
int harden_dnssec_stripped;
|
||||
int harden_referral_path;
|
||||
int use_caps_bits_for_id;
|
||||
@@ -339,23 +339,23 @@ index 1ca8686a..d91b19ec 100644
|
||||
struct config_strlist* private_domain;
|
||||
size_t unwanted_threshold;
|
||||
diff --git a/util/config_file.c b/util/config_file.c
|
||||
index 969d664b..8d94b008 100644
|
||||
index b1e767b3..5eb3c099 100644
|
||||
--- a/util/config_file.c
|
||||
+++ b/util/config_file.c
|
||||
@@ -231,6 +231,7 @@ config_create(void)
|
||||
cfg->harden_referral_path = 0;
|
||||
@@ -247,6 +247,7 @@ config_create(void)
|
||||
cfg->harden_algo_downgrade = 0;
|
||||
cfg->harden_unknown_additional = 0;
|
||||
cfg->use_caps_bits_for_id = 0;
|
||||
+ cfg->aaaa_filter = 0; /* ASN: default is disabled */
|
||||
cfg->caps_whitelist = NULL;
|
||||
cfg->private_address = NULL;
|
||||
cfg->private_domain = NULL;
|
||||
diff --git a/util/config_file.h b/util/config_file.h
|
||||
index c7c9a0a4..e3aa15b0 100644
|
||||
index 44ac036b..1e59ab07 100644
|
||||
--- a/util/config_file.h
|
||||
+++ b/util/config_file.h
|
||||
@@ -285,6 +285,8 @@ struct config_file {
|
||||
int harden_algo_downgrade;
|
||||
@@ -311,6 +311,8 @@ struct config_file {
|
||||
int harden_unknown_additional;
|
||||
/** use 0x20 bits in query as random ID bits */
|
||||
int use_caps_bits_for_id;
|
||||
+ /** ASN: enable AAAA filter? */
|
||||
@@ -364,10 +364,10 @@ index c7c9a0a4..e3aa15b0 100644
|
||||
struct config_strlist* caps_whitelist;
|
||||
/** strip away these private addrs from answers, no DNS Rebinding */
|
||||
diff --git a/util/configlexer.lex b/util/configlexer.lex
|
||||
index 34a0e5dd..c890be2a 100644
|
||||
index bc258673..76aab170 100644
|
||||
--- a/util/configlexer.lex
|
||||
+++ b/util/configlexer.lex
|
||||
@@ -317,6 +317,7 @@ use-caps-for-id{COLON} { YDVAR(1, VAR_USE_CAPS_FOR_ID) }
|
||||
@@ -327,6 +327,7 @@ use-caps-for-id{COLON} { YDVAR(1, VAR_USE_CAPS_FOR_ID) }
|
||||
caps-whitelist{COLON} { YDVAR(1, VAR_CAPS_WHITELIST) }
|
||||
caps-exempt{COLON} { YDVAR(1, VAR_CAPS_WHITELIST) }
|
||||
unwanted-reply-threshold{COLON} { YDVAR(1, VAR_UNWANTED_REPLY_THRESHOLD) }
|
||||
@@ -376,10 +376,10 @@ index 34a0e5dd..c890be2a 100644
|
||||
private-domain{COLON} { YDVAR(1, VAR_PRIVATE_DOMAIN) }
|
||||
prefetch-key{COLON} { YDVAR(1, VAR_PREFETCH_KEY) }
|
||||
diff --git a/util/configparser.y b/util/configparser.y
|
||||
index d4f965f9..8cc237c6 100644
|
||||
index 82e1d878..dc19bed5 100644
|
||||
--- a/util/configparser.y
|
||||
+++ b/util/configparser.y
|
||||
@@ -97,6 +97,7 @@ extern struct config_parser_state* cfg_parser;
|
||||
@@ -100,6 +100,7 @@ extern struct config_parser_state* cfg_parser;
|
||||
%token VAR_STATISTICS_CUMULATIVE VAR_OUTGOING_PORT_PERMIT
|
||||
%token VAR_OUTGOING_PORT_AVOID VAR_DLV_ANCHOR_FILE VAR_DLV_ANCHOR
|
||||
%token VAR_NEG_CACHE_SIZE VAR_HARDEN_REFERRAL_PATH VAR_PRIVATE_ADDRESS
|
||||
@@ -387,7 +387,7 @@ index d4f965f9..8cc237c6 100644
|
||||
%token VAR_PRIVATE_DOMAIN VAR_REMOTE_CONTROL VAR_CONTROL_ENABLE
|
||||
%token VAR_CONTROL_INTERFACE VAR_CONTROL_PORT VAR_SERVER_KEY_FILE
|
||||
%token VAR_SERVER_CERT_FILE VAR_CONTROL_KEY_FILE VAR_CONTROL_CERT_FILE
|
||||
@@ -247,6 +248,7 @@ content_server: server_num_threads | server_verbosity | server_port |
|
||||
@@ -276,6 +277,7 @@ content_server: server_num_threads | server_verbosity | server_port |
|
||||
server_dlv_anchor_file | server_dlv_anchor | server_neg_cache_size |
|
||||
server_harden_referral_path | server_private_address |
|
||||
server_private_domain | server_extended_statistics |
|
||||
@@ -395,7 +395,7 @@ index d4f965f9..8cc237c6 100644
|
||||
server_local_data_ptr | server_jostle_timeout |
|
||||
server_unwanted_reply_threshold | server_log_time_ascii |
|
||||
server_domain_insecure | server_val_sig_skew_min |
|
||||
@@ -1754,6 +1756,15 @@ server_caps_whitelist: VAR_CAPS_WHITELIST STRING_ARG
|
||||
@@ -1932,6 +1934,15 @@ server_caps_whitelist: VAR_CAPS_WHITELIST STRING_ARG
|
||||
yyerror("out of memory");
|
||||
}
|
||||
;
|
||||
|
||||
@@ -0,0 +1,325 @@
|
||||
diff --git a/sldns/keyraw.c b/sldns/keyraw.c
|
||||
index 42a9262a3..cc6406a56 100644
|
||||
--- a/sldns/keyraw.c
|
||||
+++ b/sldns/keyraw.c
|
||||
@@ -85,7 +85,7 @@ sldns_rr_dnskey_key_size_raw(const unsigned char* keydata,
|
||||
}
|
||||
break;
|
||||
#ifdef USE_GOST
|
||||
- case LDNS_ECC_GOST:
|
||||
+ case LDNS_ECC_GOST12:
|
||||
return 512;
|
||||
#endif
|
||||
#ifdef USE_ECDSA
|
||||
@@ -146,7 +146,7 @@ sldns_key_EVP_load_gost_id(void)
|
||||
if(gost_id) return gost_id;
|
||||
|
||||
/* see if configuration loaded gost implementation from other engine*/
|
||||
- meth = EVP_PKEY_asn1_find_str(NULL, "gost2001", -1);
|
||||
+ meth = EVP_PKEY_asn1_find_str(NULL, "gost2012_256", -1);
|
||||
if(meth) {
|
||||
EVP_PKEY_asn1_get0_info(&gost_id, NULL, NULL, NULL, NULL, meth);
|
||||
return gost_id;
|
||||
@@ -170,7 +170,7 @@ sldns_key_EVP_load_gost_id(void)
|
||||
return 0;
|
||||
}
|
||||
|
||||
- meth = EVP_PKEY_asn1_find_str(&e, "gost2001", -1);
|
||||
+ meth = EVP_PKEY_asn1_find_str(&e, "gost2012_256", -1);
|
||||
if(!meth) {
|
||||
/* algo not found */
|
||||
ENGINE_finish(e);
|
||||
@@ -536,12 +536,17 @@ EVP_PKEY* sldns_key_rsa2pkey_raw(unsigned char* key, size_t len)
|
||||
EVP_PKEY*
|
||||
sldns_gost2pkey_raw(unsigned char* key, size_t keylen)
|
||||
{
|
||||
- /* prefix header for X509 encoding */
|
||||
- uint8_t asn[37] = { 0x30, 0x63, 0x30, 0x1c, 0x06, 0x06, 0x2a, 0x85,
|
||||
- 0x03, 0x02, 0x02, 0x13, 0x30, 0x12, 0x06, 0x07, 0x2a, 0x85,
|
||||
- 0x03, 0x02, 0x02, 0x23, 0x01, 0x06, 0x07, 0x2a, 0x85, 0x03,
|
||||
- 0x02, 0x02, 0x1e, 0x01, 0x03, 0x43, 0x00, 0x04, 0x40};
|
||||
- unsigned char encoded[37+64];
|
||||
+ /* prefix header for X509 encoding
|
||||
+ *
|
||||
+ * note: based on draft-makarenko-gost2012-dnssec-01 (pre-RFC9558 and it DOES work!)
|
||||
+ * ASN1 header described in RFC9558 is not suitable due to d2i_PUBKEY() works with
|
||||
+ * non-compressed public keys (two additional bytes 0x04, 0x40 at the end of header)
|
||||
+ */
|
||||
+ uint8_t asn[32] = { 0x30, 0x5e, 0x30, 0x17, 0x06, 0x08, 0x2a, 0x85,
|
||||
+ 0x03, 0x07, 0x01, 0x01, 0x01, 0x01, 0x30, 0x0b,
|
||||
+ 0x06, 0x09, 0x2a, 0x85, 0x03, 0x07, 0x01, 0x02,
|
||||
+ 0x01, 0x01, 0x01, 0x03, 0x43, 0x00, 0x04, 0x40 };
|
||||
+ unsigned char encoded[32+64];
|
||||
const unsigned char* pp;
|
||||
if(keylen != 64) {
|
||||
/* key wrong size */
|
||||
@@ -549,8 +554,8 @@ sldns_gost2pkey_raw(unsigned char* key, size_t keylen)
|
||||
}
|
||||
|
||||
/* create evp_key */
|
||||
- memmove(encoded, asn, 37);
|
||||
- memmove(encoded+37, key, 64);
|
||||
+ memmove(encoded, asn, 32);
|
||||
+ memmove(encoded+32, key, 64);
|
||||
pp = (unsigned char*)&encoded[0];
|
||||
|
||||
return d2i_PUBKEY(NULL, &pp, (int)sizeof(encoded));
|
||||
diff --git a/sldns/rrdef.h b/sldns/rrdef.h
|
||||
index bbc3d5b86..7d5f3c057 100644
|
||||
--- a/sldns/rrdef.h
|
||||
+++ b/sldns/rrdef.h
|
||||
@@ -384,11 +384,12 @@ enum sldns_enum_algorithm
|
||||
LDNS_RSASHA1_NSEC3 = 7,
|
||||
LDNS_RSASHA256 = 8, /* RFC 5702 */
|
||||
LDNS_RSASHA512 = 10, /* RFC 5702 */
|
||||
- LDNS_ECC_GOST = 12, /* RFC 5933 */
|
||||
+ LDNS_ECC_GOST = 12, /* RFC 5933, deprecated */
|
||||
LDNS_ECDSAP256SHA256 = 13, /* RFC 6605 */
|
||||
LDNS_ECDSAP384SHA384 = 14, /* RFC 6605 */
|
||||
LDNS_ED25519 = 15, /* RFC 8080 */
|
||||
LDNS_ED448 = 16, /* RFC 8080 */
|
||||
+ LDNS_ECC_GOST12 = 23, /* RFC 9558 */
|
||||
LDNS_INDIRECT = 252,
|
||||
LDNS_PRIVATEDNS = 253,
|
||||
LDNS_PRIVATEOID = 254
|
||||
@@ -402,8 +403,9 @@ enum sldns_enum_hash
|
||||
{
|
||||
LDNS_SHA1 = 1, /* RFC 4034 */
|
||||
LDNS_SHA256 = 2, /* RFC 4509 */
|
||||
- LDNS_HASH_GOST = 3, /* RFC 5933 */
|
||||
- LDNS_SHA384 = 4 /* RFC 6605 */
|
||||
+ LDNS_HASH_GOST = 3, /* RFC 5933, deprecated */
|
||||
+ LDNS_SHA384 = 4, /* RFC 6605 */
|
||||
+ LDNS_HASH_GOST12 = 5 /* RFC 9558 */
|
||||
};
|
||||
typedef enum sldns_enum_hash sldns_hash;
|
||||
|
||||
diff --git a/sldns/wire2str.c b/sldns/wire2str.c
|
||||
index 75b8f37b0..b4c4755e6 100644
|
||||
--- a/sldns/wire2str.c
|
||||
+++ b/sldns/wire2str.c
|
||||
@@ -45,11 +45,12 @@ static sldns_lookup_table sldns_algorithms_data[] = {
|
||||
{ LDNS_RSASHA1_NSEC3, "RSASHA1-NSEC3-SHA1" },
|
||||
{ LDNS_RSASHA256, "RSASHA256"},
|
||||
{ LDNS_RSASHA512, "RSASHA512"},
|
||||
- { LDNS_ECC_GOST, "ECC-GOST"},
|
||||
+ { LDNS_ECC_GOST, "ECC-GOST"}, /* deprecated */
|
||||
{ LDNS_ECDSAP256SHA256, "ECDSAP256SHA256"},
|
||||
{ LDNS_ECDSAP384SHA384, "ECDSAP384SHA384"},
|
||||
{ LDNS_ED25519, "ED25519"},
|
||||
{ LDNS_ED448, "ED448"},
|
||||
+ { LDNS_ECC_GOST12, "ECC-GOST12"},
|
||||
{ LDNS_INDIRECT, "INDIRECT" },
|
||||
{ LDNS_PRIVATEDNS, "PRIVATEDNS" },
|
||||
{ LDNS_PRIVATEOID, "PRIVATEOID" },
|
||||
@@ -61,8 +62,9 @@ sldns_lookup_table* sldns_algorithms = sldns_algorithms_data;
|
||||
static sldns_lookup_table sldns_hashes_data[] = {
|
||||
{ LDNS_SHA1, "SHA1" },
|
||||
{ LDNS_SHA256, "SHA256" },
|
||||
- { LDNS_HASH_GOST, "HASH-GOST" },
|
||||
+ { LDNS_HASH_GOST, "HASH-GOST" }, /* deprecated */
|
||||
{ LDNS_SHA384, "SHA384" },
|
||||
+ { LDNS_HASH_GOST12, "HASH-GOST12" },
|
||||
{ 0, NULL }
|
||||
};
|
||||
sldns_lookup_table* sldns_hashes = sldns_hashes_data;
|
||||
diff --git a/testcode/unitverify.c b/testcode/unitverify.c
|
||||
index fcf2e2ffe..4a33e9f6a 100644
|
||||
--- a/testcode/unitverify.c
|
||||
+++ b/testcode/unitverify.c
|
||||
@@ -696,7 +696,7 @@ verify_test(void)
|
||||
#endif
|
||||
#ifdef USE_GOST
|
||||
if(sldns_key_EVP_load_gost_id())
|
||||
- verifytest_file(SRCDIRSTR "/testdata/test_sigs.gost", "20090807060504");
|
||||
+ verifytest_file(SRCDIRSTR "/testdata/test_sigs.gost12", "20251226060504");
|
||||
else printf("Warning: skipped GOST, openssl does not provide gost.\n");
|
||||
#endif
|
||||
#ifdef USE_ECDSA
|
||||
diff --git a/testdata/test_sigs.gost12 b/testdata/test_sigs.gost12
|
||||
new file mode 100644
|
||||
index 000000000..72a250cff
|
||||
--- /dev/null
|
||||
+++ b/testdata/test_sigs.gost12
|
||||
@@ -0,0 +1,39 @@
|
||||
+; Signature test file
|
||||
+
|
||||
+; first entry is a DNSKEY answer, with the DNSKEY rrset used for verification.
|
||||
+; later entries are verified with it.
|
||||
+
|
||||
+; Test GOST signatures using algo number 23.
|
||||
+
|
||||
+ENTRY_BEGIN
|
||||
+SECTION QUESTION
|
||||
+nlnetlabs.nl. IN DNSKEY
|
||||
+SECTION ANSWER
|
||||
+nlnetlabs.nl. 3600 IN DNSKEY 256 3 23 cdOtkEcb6NhcdOpIbPYtWyWxdlUiKgtKQbYg3lIjtG7i3fYjUID9zyOgoQEiV9wuGCfrw5cNsnvNw+8HiVFK4g== ;{id = 12301 (zsk), size = 512b}
|
||||
+ENTRY_END
|
||||
+
|
||||
+; entry to test
|
||||
+ENTRY_BEGIN
|
||||
+SECTION QUESTION
|
||||
+open.nlnetlabs.nl. IN A
|
||||
+SECTION ANSWER
|
||||
+open.nlnetlabs.nl. 600 IN A 213.154.224.1
|
||||
+open.nlnetlabs.nl. 600 IN RRSIG A 23 3 600 20260122084903 20251225084903 12301 nlnetlabs.nl. I12wYNs96DxMy26CWx296/sWMJAFg4nNXBo0sw7PnuMbJW5NFAmZYtFWhUdOWn4umaiodYOAmKG8Zg/OKvEtAQ==
|
||||
+ENTRY_END
|
||||
+
|
||||
+ENTRY_BEGIN
|
||||
+SECTION QUESTION
|
||||
+open.nlnetlabs.nl. IN AAAA
|
||||
+SECTION ANSWER
|
||||
+open.nlnetlabs.nl. 600 IN AAAA 2001:7b8:206:1::1
|
||||
+open.nlnetlabs.nl. 600 IN AAAA 2001:7b8:206:1::53
|
||||
+open.nlnetlabs.nl. 600 IN RRSIG AAAA 23 3 600 20260122084903 20251225084903 12301 nlnetlabs.nl. J0jHa+CP8HM6UDa2+uYgaze2mfpJTh2hkZ2KwMTYb5sfL6iBmxxql0c/403Itk4fMfYBMGn7zfzDQ+CxnCgSWw==
|
||||
+ENTRY_END
|
||||
+
|
||||
+ENTRY_BEGIN
|
||||
+SECTION QUESTION
|
||||
+open.nlnetlabs.nl. IN NSEC
|
||||
+SECTION ANSWER
|
||||
+open.nlnetlabs.nl. 86400 IN NSEC nlnetlabs.nl. A AAAA RRSIG NSEC
|
||||
+open.nlnetlabs.nl. 86400 IN RRSIG NSEC 23 3 86400 20260122084903 20251225084903 12301 nlnetlabs.nl. INCLYe9vAaNYaYx5Ay3Q6QdX+wPW9sMRvVlGt/jUEGgCi+88QlV80CT1oHrhRI66I14Wk6NRAGZRNx1tUPSHSg==
|
||||
+ENTRY_END
|
||||
diff --git a/validator/val_secalgo.c b/validator/val_secalgo.c
|
||||
index be8347b1b..4f621a309 100644
|
||||
--- a/validator/val_secalgo.c
|
||||
+++ b/validator/val_secalgo.c
|
||||
@@ -246,10 +246,10 @@ ds_digest_size_supported(int algo)
|
||||
return SHA256_DIGEST_LENGTH;
|
||||
#endif
|
||||
#ifdef USE_GOST
|
||||
- case LDNS_HASH_GOST:
|
||||
+ case LDNS_HASH_GOST12:
|
||||
/* we support GOST if it can be loaded */
|
||||
(void)sldns_key_EVP_load_gost_id();
|
||||
- if(EVP_get_digestbyname("md_gost94"))
|
||||
+ if(EVP_get_digestbyname("md_gost12_256"))
|
||||
return 32;
|
||||
else return 0;
|
||||
#endif
|
||||
@@ -265,9 +265,9 @@ ds_digest_size_supported(int algo)
|
||||
#ifdef USE_GOST
|
||||
/** Perform GOST hash */
|
||||
static int
|
||||
-do_gost94(unsigned char* data, size_t len, unsigned char* dest)
|
||||
+do_gost12(unsigned char* data, size_t len, unsigned char* dest)
|
||||
{
|
||||
- const EVP_MD* md = EVP_get_digestbyname("md_gost94");
|
||||
+ const EVP_MD* md = EVP_get_digestbyname("md_gost12_256");
|
||||
if(!md)
|
||||
return 0;
|
||||
return sldns_digest_evp(data, (unsigned int)len, dest, md);
|
||||
@@ -302,8 +302,8 @@ secalgo_ds_digest(int algo, unsigned char* buf, size_t len,
|
||||
return 1;
|
||||
#endif
|
||||
#ifdef USE_GOST
|
||||
- case LDNS_HASH_GOST:
|
||||
- if(do_gost94(buf, len, res))
|
||||
+ case LDNS_HASH_GOST12:
|
||||
+ if(do_gost12(buf, len, res))
|
||||
return 1;
|
||||
break;
|
||||
#endif
|
||||
@@ -384,7 +384,7 @@ dnskey_algo_id_is_supported(int id)
|
||||
#endif
|
||||
|
||||
#ifdef USE_GOST
|
||||
- case LDNS_ECC_GOST:
|
||||
+ case LDNS_ECC_GOST12:
|
||||
/* we support GOST if it can be loaded */
|
||||
return sldns_key_EVP_load_gost_id();
|
||||
#endif
|
||||
@@ -612,17 +612,17 @@ setup_key_digest(int algo, EVP_PKEY** evp_key, const EVP_MD** digest_type,
|
||||
|
||||
break;
|
||||
#ifdef USE_GOST
|
||||
- case LDNS_ECC_GOST:
|
||||
+ case LDNS_ECC_GOST12:
|
||||
*evp_key = sldns_gost2pkey_raw(key, keylen);
|
||||
if(!*evp_key) {
|
||||
verbose(VERB_QUERY, "verify: "
|
||||
"sldns_gost2pkey_raw failed");
|
||||
return 0;
|
||||
}
|
||||
- *digest_type = EVP_get_digestbyname("md_gost94");
|
||||
+ *digest_type = EVP_get_digestbyname("md_gost12_256");
|
||||
if(!*digest_type) {
|
||||
verbose(VERB_QUERY, "verify: "
|
||||
- "EVP_getdigest md_gost94 failed");
|
||||
+ "EVP_getdigest md_gost12_256 failed");
|
||||
return 0;
|
||||
}
|
||||
break;
|
||||
@@ -964,7 +964,7 @@ ds_digest_size_supported(int algo)
|
||||
return SHA384_LENGTH;
|
||||
#endif
|
||||
/* GOST not supported in NSS */
|
||||
- case LDNS_HASH_GOST:
|
||||
+ case LDNS_HASH_GOST12:
|
||||
default: break;
|
||||
}
|
||||
return 0;
|
||||
@@ -991,7 +991,7 @@ secalgo_ds_digest(int algo, unsigned char* buf, size_t len,
|
||||
return HASH_HashBuf(HASH_AlgSHA384, res, buf, len)
|
||||
== SECSuccess;
|
||||
#endif
|
||||
- case LDNS_HASH_GOST:
|
||||
+ case LDNS_HASH_GOST12:
|
||||
default:
|
||||
verbose(VERB_QUERY, "unknown DS digest algorithm %d",
|
||||
algo);
|
||||
@@ -1031,7 +1031,7 @@ dnskey_algo_id_is_supported(int id)
|
||||
case LDNS_ECDSAP384SHA384:
|
||||
return PK11_TokenExists(CKM_ECDSA);
|
||||
#endif
|
||||
- case LDNS_ECC_GOST:
|
||||
+ case LDNS_ECC_GOST12:
|
||||
default:
|
||||
return 0;
|
||||
}
|
||||
@@ -1352,7 +1352,7 @@ nss_setup_key_digest(int algo, SECKEYPublicKey** pubkey, HASH_HashType* htype,
|
||||
/* no prefix for DSA verification */
|
||||
break;
|
||||
#endif /* USE_ECDSA */
|
||||
- case LDNS_ECC_GOST:
|
||||
+ case LDNS_ECC_GOST12:
|
||||
default:
|
||||
verbose(VERB_QUERY, "verify: unknown algorithm %d",
|
||||
algo);
|
||||
@@ -1675,7 +1675,7 @@ ds_digest_size_supported(int algo)
|
||||
return SHA384_DIGEST_SIZE;
|
||||
#endif
|
||||
/* GOST not supported */
|
||||
- case LDNS_HASH_GOST:
|
||||
+ case LDNS_ECC_GOST12:
|
||||
default:
|
||||
break;
|
||||
}
|
||||
@@ -1700,7 +1700,7 @@ secalgo_ds_digest(int algo, unsigned char* buf, size_t len,
|
||||
return _digest_nettle(SHA384_DIGEST_SIZE, buf, len, res);
|
||||
|
||||
#endif
|
||||
- case LDNS_HASH_GOST:
|
||||
+ case LDNS_ECC_GOST12:
|
||||
default:
|
||||
verbose(VERB_QUERY, "unknown DS digest algorithm %d",
|
||||
algo);
|
||||
@@ -1744,7 +1744,7 @@ dnskey_algo_id_is_supported(int id)
|
||||
return 1;
|
||||
#endif
|
||||
case LDNS_RSAMD5: /* RFC 6725 deprecates RSAMD5 */
|
||||
- case LDNS_ECC_GOST:
|
||||
+ case LDNS_ECC_GOST12:
|
||||
default:
|
||||
return 0;
|
||||
}
|
||||
@@ -2103,7 +2103,7 @@ verify_canonrrset(sldns_buffer* buf, int algo, unsigned char* sigblock,
|
||||
return sec_status_secure;
|
||||
#endif
|
||||
case LDNS_RSAMD5:
|
||||
- case LDNS_ECC_GOST:
|
||||
+ case LDNS_ECC_GOST12:
|
||||
default:
|
||||
*reason = "unable to verify signature, unknown algorithm";
|
||||
return sec_status_bogus;
|
||||
@@ -1,21 +1,22 @@
|
||||
#!/usr/bin/env bash
|
||||
OPENSSL_VERSION=1.1.1d
|
||||
|
||||
echo "Downloading OpenSSL"
|
||||
if ! curl -L -k -s -o openssl-1.1.1d.tar.gz https://www.openssl.org/source/openssl-1.1.1d.tar.gz;
|
||||
if ! curl -L -k -s -o openssl-$OPENSSL_VERSION.tar.gz https://www.openssl.org/source/openssl-$OPENSSL_VERSION.tar.gz;
|
||||
then
|
||||
echo "Failed to download OpenSSL"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
echo "Unpacking OpenSSL"
|
||||
rm -rf ./openssl-1.1.1d
|
||||
if ! tar -xf openssl-1.1.1d.tar.gz;
|
||||
rm -rf ./openssl-$OPENSSL_VERSION
|
||||
if ! tar -xf openssl-$OPENSSL_VERSION.tar.gz;
|
||||
then
|
||||
echo "Failed to unpack OpenSSL"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
cd openssl-1.1.1d || exit 1
|
||||
cd openssl-$OPENSSL_VERSION || exit 1
|
||||
|
||||
if ! cp ../contrib/ios/15-ios.conf Configurations/; then
|
||||
echo "Failed to copy OpenSSL ios config"
|
||||
@@ -27,7 +28,8 @@ fi
|
||||
# Also see https://github.com/openssl/openssl/issues/7607.
|
||||
if ! patch -u -p0 < ../contrib/ios/openssl.patch; then
|
||||
echo "Failed to patch OpenSSL"
|
||||
exit 1
|
||||
# the partial patch may be useful.
|
||||
#exit 1
|
||||
fi
|
||||
|
||||
echo "Configuring OpenSSL"
|
||||
|
||||
@@ -175,6 +175,7 @@ fi
|
||||
# For example, remove 4.3, 6.2, and 6.1 if they are not installed. We go back to
|
||||
# the 1.0 SDKs because Apple WatchOS uses low numbers, like 2.0 and 2.1.
|
||||
XCODE_SDK=
|
||||
if test -z "$SDK_VERSION"; then
|
||||
for i in $(seq -f "%.1f" 30.0 -0.1 1.0)
|
||||
do
|
||||
if [ -d "$XCODE_DEVELOPER_SDK/Developer/SDKs/$IOS_SDK$i.sdk" ]; then
|
||||
@@ -182,6 +183,10 @@ do
|
||||
break
|
||||
fi
|
||||
done
|
||||
else
|
||||
i="$SDK_VERSION"
|
||||
XCODE_SDK="$IOS_SDK$i.sdk"
|
||||
fi
|
||||
|
||||
# Error checking
|
||||
if [ -z "$XCODE_SDK" ]; then
|
||||
|
||||
@@ -38,11 +38,17 @@
|
||||
; - `LockPersonality=yes` locks down the personality system call so that the
|
||||
; kernel execution domain may not be changed from the default.
|
||||
;
|
||||
; - With /etc/systemd/network/*.network a setting to make sure the network
|
||||
; is not considered online too early, can reduce network unreachable
|
||||
; errors on server start:
|
||||
; [Link]
|
||||
; RequiredForOnline=routable
|
||||
;
|
||||
[Unit]
|
||||
Description=Validating, recursive, and caching DNS resolver
|
||||
Documentation=man:unbound(8)
|
||||
After=network-online.target
|
||||
Wants=network-online.target
|
||||
Before=nss-lookup.target
|
||||
|
||||
[Install]
|
||||
@@ -53,7 +59,7 @@ ExecReload=+/bin/kill -HUP $MAINPID
|
||||
ExecStart=@UNBOUND_SBIN_DIR@/unbound -d -p
|
||||
NotifyAccess=main
|
||||
Type=notify
|
||||
CapabilityBoundingSet=CAP_NET_BIND_SERVICE CAP_SETGID CAP_SETUID CAP_SYS_CHROOT CAP_SYS_RESOURCE CAP_NET_RAW
|
||||
CapabilityBoundingSet=CAP_NET_BIND_SERVICE CAP_SETGID CAP_SETUID CAP_SYS_CHROOT CAP_SYS_RESOURCE CAP_NET_ADMIN
|
||||
MemoryDenyWriteExecute=true
|
||||
NoNewPrivileges=true
|
||||
PrivateDevices=true
|
||||
|
||||
@@ -26,7 +26,7 @@ ExecReload=+/bin/kill -HUP $MAINPID
|
||||
ExecStart=@UNBOUND_SBIN_DIR@/unbound -d -p
|
||||
NotifyAccess=main
|
||||
Type=notify
|
||||
CapabilityBoundingSet=CAP_NET_BIND_SERVICE CAP_SETGID CAP_SETUID CAP_SYS_CHROOT CAP_SYS_RESOURCE CAP_NET_RAW
|
||||
CapabilityBoundingSet=CAP_NET_BIND_SERVICE CAP_SETGID CAP_SETUID CAP_SYS_CHROOT CAP_SYS_RESOURCE CAP_NET_ADMIN
|
||||
MemoryDenyWriteExecute=true
|
||||
NoNewPrivileges=true
|
||||
PrivateDevices=true
|
||||
|
||||
+238
-109
@@ -62,84 +62,231 @@
|
||||
#include "sldns/wire2str.h"
|
||||
#include "sldns/str2wire.h"
|
||||
|
||||
/** dump one rrset zonefile line */
|
||||
static int
|
||||
dump_rrset_line(RES* ssl, struct ub_packed_rrset_key* k, time_t now, size_t i)
|
||||
static void spool_txt_printf(struct config_strlist_head* txt,
|
||||
const char* format, ...) ATTR_FORMAT(printf, 2, 3);
|
||||
|
||||
/** Append to strlist at end, and log error if out of memory. */
|
||||
static void
|
||||
spool_txt_string(struct config_strlist_head* txt, char* str)
|
||||
{
|
||||
char s[65535];
|
||||
if(!packed_rr_to_string(k, i, now, s, sizeof(s))) {
|
||||
return ssl_printf(ssl, "BADRR\n");
|
||||
if(!cfg_strlist_append(txt, strdup(str))) {
|
||||
log_err("out of memory in spool text");
|
||||
}
|
||||
return ssl_printf(ssl, "%s", s);
|
||||
}
|
||||
|
||||
/** Spool txt to spool list. */
|
||||
static void
|
||||
spool_txt_vmsg(struct config_strlist_head* txt, const char* format,
|
||||
va_list args)
|
||||
{
|
||||
char msg[65535];
|
||||
vsnprintf(msg, sizeof(msg), format, args);
|
||||
spool_txt_string(txt, msg);
|
||||
}
|
||||
|
||||
/** Print item to spool list. On alloc failure the list is as before. */
|
||||
static void
|
||||
spool_txt_printf(struct config_strlist_head* txt, const char* format, ...)
|
||||
{
|
||||
va_list args;
|
||||
va_start(args, format);
|
||||
spool_txt_vmsg(txt, format, args);
|
||||
va_end(args);
|
||||
}
|
||||
|
||||
/** dump one rrset zonefile line */
|
||||
static void
|
||||
dump_rrset_line(struct config_strlist_head* txt, struct ub_packed_rrset_key* k,
|
||||
time_t now, size_t i)
|
||||
{
|
||||
char s[65535*4+2048];
|
||||
if(!packed_rr_to_string(k, i, now, s, sizeof(s))) {
|
||||
spool_txt_string(txt, "BADRR\n");
|
||||
return;
|
||||
}
|
||||
spool_txt_string(txt, s);
|
||||
}
|
||||
|
||||
/** dump rrset key and data info */
|
||||
static int
|
||||
dump_rrset(RES* ssl, struct ub_packed_rrset_key* k,
|
||||
static void
|
||||
dump_rrset(struct config_strlist_head* txt, struct ub_packed_rrset_key* k,
|
||||
struct packed_rrset_data* d, time_t now)
|
||||
{
|
||||
size_t i;
|
||||
/* rd lock held by caller */
|
||||
if(!k || !d) return 1;
|
||||
if(k->id == 0) return 1; /* deleted */
|
||||
if(d->ttl < now) return 1; /* expired */
|
||||
if(!k || !d) return;
|
||||
if(k->id == 0) return; /* deleted */
|
||||
if(d->ttl < now) return; /* expired */
|
||||
|
||||
/* meta line */
|
||||
if(!ssl_printf(ssl, ";rrset%s " ARG_LL "d %u %u %d %d\n",
|
||||
spool_txt_printf(txt, ";rrset%s " ARG_LL "d %u %u %d %d\n",
|
||||
(k->rk.flags & PACKED_RRSET_NSEC_AT_APEX)?" nsec_apex":"",
|
||||
(long long)(d->ttl - now),
|
||||
(unsigned)d->count, (unsigned)d->rrsig_count,
|
||||
(int)d->trust, (int)d->security
|
||||
))
|
||||
return 0;
|
||||
);
|
||||
for(i=0; i<d->count + d->rrsig_count; i++) {
|
||||
if(!dump_rrset_line(ssl, k, now, i))
|
||||
dump_rrset_line(txt, k, now, i);
|
||||
}
|
||||
}
|
||||
|
||||
/** Spool strlist to the output. */
|
||||
static int
|
||||
spool_strlist(RES* ssl, struct config_strlist* list)
|
||||
{
|
||||
struct config_strlist* s;
|
||||
for(s=list; s; s=s->next) {
|
||||
if(!ssl_printf(ssl, "%s", s->str))
|
||||
return 0;
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
/** dump lruhash rrset cache */
|
||||
/** dump lruhash cache and call callback for every item. */
|
||||
static int
|
||||
dump_rrset_lruhash(RES* ssl, struct lruhash* h, time_t now)
|
||||
dump_lruhash(struct lruhash* table,
|
||||
void (*func)(struct lruhash_entry*, struct config_strlist_head*, void*),
|
||||
RES* ssl, void* arg)
|
||||
{
|
||||
struct lruhash_entry* e;
|
||||
/* lruhash already locked by caller */
|
||||
/* walk in order of lru; best first */
|
||||
for(e=h->lru_start; e; e = e->lru_next) {
|
||||
lock_rw_rdlock(&e->lock);
|
||||
if(!dump_rrset(ssl, (struct ub_packed_rrset_key*)e->key,
|
||||
(struct packed_rrset_data*)e->data, now)) {
|
||||
lock_rw_unlock(&e->lock);
|
||||
int just_started = 1;
|
||||
int not_done = 1;
|
||||
hashvalue_type hash;
|
||||
size_t num = 0; /* number of entries processed. */
|
||||
size_t max = 2; /* number of entries after which it unlocks. */
|
||||
struct config_strlist_head txt; /* Text strings spooled. */
|
||||
memset(&txt, 0, sizeof(txt));
|
||||
|
||||
while(not_done) {
|
||||
size_t i; /* hash bin. */
|
||||
/* Process a number of items. */
|
||||
num = 0;
|
||||
lock_quick_lock(&table->lock);
|
||||
if(just_started) {
|
||||
i = 0;
|
||||
} else {
|
||||
i = hash&table->size_mask;
|
||||
}
|
||||
while(num < max) {
|
||||
/* Process bin. */
|
||||
int found = 0;
|
||||
size_t num_bin = 0;
|
||||
struct lruhash_bin* bin = &table->array[i];
|
||||
struct lruhash_entry* e;
|
||||
lock_quick_lock(&bin->lock);
|
||||
for(e = bin->overflow_list; e; e = e->overflow_next) {
|
||||
/* Entry e is locked by the func. */
|
||||
func(e, &txt, arg);
|
||||
num_bin++;
|
||||
}
|
||||
lock_quick_unlock(&bin->lock);
|
||||
/* This addition of bin number of entries may take
|
||||
* it over the max. */
|
||||
num += num_bin;
|
||||
|
||||
/* Move to next bin. */
|
||||
/* Find one with an entry, with a hash value, so we
|
||||
* can continue from the hash value. The hash value
|
||||
* can be indexed also if the array changes size. */
|
||||
i++;
|
||||
while(i < table->size) {
|
||||
bin = &table->array[i];
|
||||
lock_quick_lock(&bin->lock);
|
||||
if(bin->overflow_list) {
|
||||
hash = bin->overflow_list->hash;
|
||||
lock_quick_unlock(&bin->lock);
|
||||
found = 1;
|
||||
just_started = 0;
|
||||
break;
|
||||
}
|
||||
lock_quick_unlock(&bin->lock);
|
||||
i++;
|
||||
}
|
||||
if(!found) {
|
||||
not_done = 0;
|
||||
break;
|
||||
}
|
||||
}
|
||||
lock_quick_unlock(&table->lock);
|
||||
/* Print the spooled items, that are collected while the
|
||||
* locks are locked. The print happens while they are not
|
||||
* locked. */
|
||||
if(txt.first) {
|
||||
if(!spool_strlist(ssl, txt.first)) {
|
||||
config_delstrlist(txt.first);
|
||||
return 0;
|
||||
}
|
||||
config_delstrlist(txt.first);
|
||||
memset(&txt, 0, sizeof(txt));
|
||||
}
|
||||
}
|
||||
/* Print the final spooled items. */
|
||||
if(txt.first) {
|
||||
if(!spool_strlist(ssl, txt.first)) {
|
||||
config_delstrlist(txt.first);
|
||||
return 0;
|
||||
}
|
||||
lock_rw_unlock(&e->lock);
|
||||
config_delstrlist(txt.first);
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
/** dump slabhash cache and call callback for every item. */
|
||||
static int
|
||||
dump_slabhash(struct slabhash* sh,
|
||||
void (*func)(struct lruhash_entry*, struct config_strlist_head*, void*),
|
||||
RES* ssl, void* arg)
|
||||
{
|
||||
/* Process a number of items at a time, then unlock the cache,
|
||||
* so that ordinary processing can continue. Keep an iteration marker
|
||||
* to continue the loop. That means the cache can change, items
|
||||
* could be inserted and deleted. And, for example, the hash table
|
||||
* can grow. */
|
||||
size_t slab;
|
||||
for(slab=0; slab<sh->size; slab++) {
|
||||
if(!dump_lruhash(sh->array[slab], func, ssl, arg))
|
||||
return 0;
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
/** Struct for dump information. */
|
||||
struct dump_info {
|
||||
/** The worker. */
|
||||
struct worker* worker;
|
||||
/** The printout connection. */
|
||||
RES* ssl;
|
||||
};
|
||||
|
||||
/** Dump the rrset cache entry */
|
||||
static void
|
||||
dump_rrset_entry(struct lruhash_entry* e, struct config_strlist_head* txt,
|
||||
void* arg)
|
||||
{
|
||||
struct dump_info* dump_info = (struct dump_info*)arg;
|
||||
lock_rw_rdlock(&e->lock);
|
||||
dump_rrset(txt, (struct ub_packed_rrset_key*)e->key,
|
||||
(struct packed_rrset_data*)e->data,
|
||||
*dump_info->worker->env.now);
|
||||
lock_rw_unlock(&e->lock);
|
||||
}
|
||||
|
||||
/** dump rrset cache */
|
||||
static int
|
||||
dump_rrset_cache(RES* ssl, struct worker* worker)
|
||||
{
|
||||
struct rrset_cache* r = worker->env.rrset_cache;
|
||||
size_t slab;
|
||||
struct dump_info dump_info;
|
||||
dump_info.worker = worker;
|
||||
dump_info.ssl = ssl;
|
||||
if(!ssl_printf(ssl, "START_RRSET_CACHE\n")) return 0;
|
||||
for(slab=0; slab<r->table.size; slab++) {
|
||||
lock_quick_lock(&r->table.array[slab]->lock);
|
||||
if(!dump_rrset_lruhash(ssl, r->table.array[slab],
|
||||
*worker->env.now)) {
|
||||
lock_quick_unlock(&r->table.array[slab]->lock);
|
||||
return 0;
|
||||
}
|
||||
lock_quick_unlock(&r->table.array[slab]->lock);
|
||||
}
|
||||
if(!dump_slabhash(&r->table, &dump_rrset_entry, ssl, &dump_info))
|
||||
return 0;
|
||||
return ssl_printf(ssl, "END_RRSET_CACHE\n");
|
||||
}
|
||||
|
||||
/** dump message to rrset reference */
|
||||
static int
|
||||
dump_msg_ref(RES* ssl, struct ub_packed_rrset_key* k)
|
||||
static void
|
||||
dump_msg_ref(struct config_strlist_head* txt, struct ub_packed_rrset_key* k)
|
||||
{
|
||||
char* nm, *tp, *cl;
|
||||
nm = sldns_wire2str_dname(k->rk.dname, k->rk.dname_len);
|
||||
@@ -149,30 +296,25 @@ dump_msg_ref(RES* ssl, struct ub_packed_rrset_key* k)
|
||||
free(nm);
|
||||
free(tp);
|
||||
free(cl);
|
||||
return ssl_printf(ssl, "BADREF\n");
|
||||
}
|
||||
if(!ssl_printf(ssl, "%s %s %s %d\n", nm, cl, tp, (int)k->rk.flags)) {
|
||||
free(nm);
|
||||
free(tp);
|
||||
free(cl);
|
||||
return 0;
|
||||
spool_txt_string(txt, "BADREF\n");
|
||||
return;
|
||||
}
|
||||
spool_txt_printf(txt, "%s %s %s %d\n", nm, cl, tp, (int)k->rk.flags);
|
||||
free(nm);
|
||||
free(tp);
|
||||
free(cl);
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
/** dump message entry */
|
||||
static int
|
||||
dump_msg(RES* ssl, struct query_info* k, struct reply_info* d, time_t now)
|
||||
static void
|
||||
dump_msg(struct config_strlist_head* txt, struct query_info* k,
|
||||
struct reply_info* d, time_t now)
|
||||
{
|
||||
size_t i;
|
||||
char* nm, *tp, *cl;
|
||||
if(!k || !d) return 1;
|
||||
if(d->ttl < now) return 1; /* expired */
|
||||
|
||||
if(!k || !d) return;
|
||||
if(d->ttl < now) return; /* expired */
|
||||
|
||||
nm = sldns_wire2str_dname(k->qname, k->qname_len);
|
||||
tp = sldns_wire2str_type(k->qtype);
|
||||
cl = sldns_wire2str_class(k->qclass);
|
||||
@@ -180,45 +322,35 @@ dump_msg(RES* ssl, struct query_info* k, struct reply_info* d, time_t now)
|
||||
free(nm);
|
||||
free(tp);
|
||||
free(cl);
|
||||
return 1; /* skip this entry */
|
||||
return; /* skip this entry */
|
||||
}
|
||||
if(!rrset_array_lock(d->ref, d->rrset_count, now)) {
|
||||
/* rrsets have timed out or do not exist */
|
||||
free(nm);
|
||||
free(tp);
|
||||
free(cl);
|
||||
return 1; /* skip this entry */
|
||||
return; /* skip this entry */
|
||||
}
|
||||
|
||||
|
||||
/* meta line */
|
||||
if(!ssl_printf(ssl, "msg %s %s %s %d %d " ARG_LL "d %d %u %u %u %d %s\n",
|
||||
nm, cl, tp,
|
||||
(int)d->flags, (int)d->qdcount,
|
||||
(long long)(d->ttl-now), (int)d->security,
|
||||
(unsigned)d->an_numrrsets,
|
||||
(unsigned)d->ns_numrrsets,
|
||||
(unsigned)d->ar_numrrsets,
|
||||
(int)d->reason_bogus,
|
||||
d->reason_bogus_str?d->reason_bogus_str:"")) {
|
||||
free(nm);
|
||||
free(tp);
|
||||
free(cl);
|
||||
rrset_array_unlock(d->ref, d->rrset_count);
|
||||
return 0;
|
||||
}
|
||||
spool_txt_printf(txt,
|
||||
"msg %s %s %s %d %d " ARG_LL "d %d %u %u %u %d %s\n",
|
||||
nm, cl, tp,
|
||||
(int)d->flags, (int)d->qdcount,
|
||||
(long long)(d->ttl-now), (int)d->security,
|
||||
(unsigned)d->an_numrrsets,
|
||||
(unsigned)d->ns_numrrsets,
|
||||
(unsigned)d->ar_numrrsets,
|
||||
(int)d->reason_bogus,
|
||||
d->reason_bogus_str?d->reason_bogus_str:"");
|
||||
free(nm);
|
||||
free(tp);
|
||||
free(cl);
|
||||
|
||||
for(i=0; i<d->rrset_count; i++) {
|
||||
if(!dump_msg_ref(ssl, d->rrsets[i])) {
|
||||
rrset_array_unlock(d->ref, d->rrset_count);
|
||||
return 0;
|
||||
}
|
||||
dump_msg_ref(txt, d->rrsets[i]);
|
||||
}
|
||||
rrset_array_unlock(d->ref, d->rrset_count);
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
/** copy msg to worker pad */
|
||||
@@ -247,49 +379,40 @@ copy_msg(struct regional* region, struct lruhash_entry* e,
|
||||
return (*k)->qname != NULL;
|
||||
}
|
||||
|
||||
/** dump lruhash msg cache */
|
||||
static int
|
||||
dump_msg_lruhash(RES* ssl, struct worker* worker, struct lruhash* h)
|
||||
/** Dump the msg entry. */
|
||||
static void
|
||||
dump_msg_entry(struct lruhash_entry* e, struct config_strlist_head* txt,
|
||||
void* arg)
|
||||
{
|
||||
struct lruhash_entry* e;
|
||||
struct dump_info* dump_info = (struct dump_info*)arg;
|
||||
struct query_info* k;
|
||||
struct reply_info* d;
|
||||
|
||||
/* lruhash already locked by caller */
|
||||
/* walk in order of lru; best first */
|
||||
for(e=h->lru_start; e; e = e->lru_next) {
|
||||
regional_free_all(worker->scratchpad);
|
||||
lock_rw_rdlock(&e->lock);
|
||||
/* make copy of rrset in worker buffer */
|
||||
if(!copy_msg(worker->scratchpad, e, &k, &d)) {
|
||||
lock_rw_unlock(&e->lock);
|
||||
return 0;
|
||||
}
|
||||
regional_free_all(dump_info->worker->scratchpad);
|
||||
/* Make copy of rrset in worker buffer. */
|
||||
lock_rw_rdlock(&e->lock);
|
||||
if(!copy_msg(dump_info->worker->scratchpad, e, &k, &d)) {
|
||||
lock_rw_unlock(&e->lock);
|
||||
/* release lock so we can lookup the rrset references
|
||||
* in the rrset cache */
|
||||
if(!dump_msg(ssl, k, d, *worker->env.now)) {
|
||||
return 0;
|
||||
}
|
||||
log_err("out of memory in dump_msg_entry");
|
||||
return;
|
||||
}
|
||||
return 1;
|
||||
lock_rw_unlock(&e->lock);
|
||||
/* Release lock so we can lookup the rrset references
|
||||
* in the rrset cache. */
|
||||
dump_msg(txt, k, d, *dump_info->worker->env.now);
|
||||
}
|
||||
|
||||
/** dump msg cache */
|
||||
static int
|
||||
dump_msg_cache(RES* ssl, struct worker* worker)
|
||||
{
|
||||
struct slabhash* sh = worker->env.msg_cache;
|
||||
size_t slab;
|
||||
struct dump_info dump_info;
|
||||
dump_info.worker = worker;
|
||||
dump_info.ssl = ssl;
|
||||
if(!ssl_printf(ssl, "START_MSG_CACHE\n")) return 0;
|
||||
for(slab=0; slab<sh->size; slab++) {
|
||||
lock_quick_lock(&sh->array[slab]->lock);
|
||||
if(!dump_msg_lruhash(ssl, worker, sh->array[slab])) {
|
||||
lock_quick_unlock(&sh->array[slab]->lock);
|
||||
return 0;
|
||||
}
|
||||
lock_quick_unlock(&sh->array[slab]->lock);
|
||||
}
|
||||
if(!dump_slabhash(worker->env.msg_cache, &dump_msg_entry, ssl,
|
||||
&dump_info))
|
||||
return 0;
|
||||
return ssl_printf(ssl, "END_MSG_CACHE\n");
|
||||
}
|
||||
|
||||
@@ -332,7 +455,7 @@ load_rr(RES* ssl, sldns_buffer* buf, struct regional* region,
|
||||
/* read the line */
|
||||
if(!ssl_read_buf(ssl, buf))
|
||||
return 0;
|
||||
if(strncmp((char*)sldns_buffer_begin(buf), "BADRR\n", 6) == 0) {
|
||||
if(strcmp((char*)sldns_buffer_begin(buf), "BADRR") == 0) {
|
||||
*go_on = 0;
|
||||
return 1;
|
||||
}
|
||||
@@ -811,12 +934,18 @@ print_dp_main(RES* ssl, struct delegpt* dp, struct dns_msg* msg)
|
||||
struct ub_packed_rrset_key* k = msg->rep->rrsets[i];
|
||||
struct packed_rrset_data* d =
|
||||
(struct packed_rrset_data*)k->entry.data;
|
||||
struct config_strlist_head txt;
|
||||
memset(&txt, 0, sizeof(txt));
|
||||
if(d->security == sec_status_bogus) {
|
||||
if(!ssl_printf(ssl, "Address is BOGUS:\n"))
|
||||
return;
|
||||
}
|
||||
if(!dump_rrset(ssl, k, d, 0))
|
||||
dump_rrset(&txt, k, d, 0);
|
||||
if(!spool_strlist(ssl, txt.first)) {
|
||||
config_delstrlist(txt.first);
|
||||
return;
|
||||
}
|
||||
config_delstrlist(txt.first);
|
||||
}
|
||||
delegpt_count_ns(dp, &n_ns, &n_miss);
|
||||
delegpt_count_addr(dp, &n_addr, &n_res, &n_avail);
|
||||
|
||||
+339
-27
@@ -79,6 +79,7 @@
|
||||
#include "util/tcp_conn_limit.h"
|
||||
#include "util/edns.h"
|
||||
#include "services/listen_dnsport.h"
|
||||
#include "services/outside_network.h"
|
||||
#include "services/cache/rrset.h"
|
||||
#include "services/cache/infra.h"
|
||||
#include "services/localzone.h"
|
||||
@@ -199,6 +200,267 @@ signal_handling_playback(struct worker* wrk)
|
||||
sig_record_reload = 0;
|
||||
}
|
||||
|
||||
#ifdef HAVE_SSL
|
||||
/* setup a listening ssl context, fatal_exit() on any failure */
|
||||
static void
|
||||
setup_listen_sslctx(void** ctx, int is_dot, int is_doh,
|
||||
struct config_file* cfg, char* chroot)
|
||||
{
|
||||
char* key = cfg->ssl_service_key;
|
||||
char* pem = cfg->ssl_service_pem;
|
||||
if(chroot && strncmp(key, chroot, strlen(chroot)) == 0)
|
||||
key += strlen(chroot);
|
||||
if(chroot && pem && strncmp(pem, chroot, strlen(chroot)) == 0)
|
||||
pem += strlen(chroot);
|
||||
if(!(*ctx = listen_sslctx_create(key, pem, NULL,
|
||||
cfg->tls_ciphers, cfg->tls_ciphersuites,
|
||||
(cfg->tls_session_ticket_keys.first &&
|
||||
cfg->tls_session_ticket_keys.first->str[0] != 0),
|
||||
is_dot, is_doh, cfg->tls_protocols))) {
|
||||
log_err("could not set up listen SSL_CTX");
|
||||
*ctx = NULL;
|
||||
}
|
||||
}
|
||||
#endif /* HAVE_SSL */
|
||||
|
||||
#ifdef HAVE_SSL
|
||||
void* daemon_setup_listen_dot_sslctx(struct daemon* daemon,
|
||||
struct config_file* cfg)
|
||||
{
|
||||
void* ctx;
|
||||
(void)setup_listen_sslctx(&ctx, 1, 0, cfg, daemon->chroot);
|
||||
return ctx;
|
||||
}
|
||||
#endif /* HAVE_SSL */
|
||||
|
||||
#ifdef HAVE_SSL
|
||||
#ifdef HAVE_NGHTTP2_NGHTTP2_H
|
||||
void* daemon_setup_listen_doh_sslctx(struct daemon* daemon,
|
||||
struct config_file* cfg)
|
||||
{
|
||||
void* ctx;
|
||||
(void)setup_listen_sslctx(&ctx, 0, 1, cfg, daemon->chroot);
|
||||
return ctx;
|
||||
}
|
||||
#endif /* HAVE_NGHTTP2_NGHTTP2_H */
|
||||
#endif /* HAVE_SSL */
|
||||
|
||||
#ifdef HAVE_SSL
|
||||
#ifdef HAVE_NGTCP2
|
||||
void* daemon_setup_listen_quic_sslctx(struct daemon* daemon,
|
||||
struct config_file* cfg)
|
||||
{
|
||||
void* ctx;
|
||||
char* chroot = daemon->chroot;
|
||||
char* key = cfg->ssl_service_key;
|
||||
char* pem = cfg->ssl_service_pem;
|
||||
if(chroot && strncmp(key, chroot, strlen(chroot)) == 0)
|
||||
key += strlen(chroot);
|
||||
if(chroot && pem && strncmp(pem, chroot, strlen(chroot)) == 0)
|
||||
pem += strlen(chroot);
|
||||
|
||||
if(!(ctx = quic_sslctx_create(key, pem, NULL))) {
|
||||
log_err("could not set up quic SSL_CTX");
|
||||
return NULL;
|
||||
}
|
||||
return ctx;
|
||||
}
|
||||
#endif /* HAVE_NGTCP2 */
|
||||
#endif /* HAVE_SSL */
|
||||
|
||||
#ifdef HAVE_SSL
|
||||
void* daemon_setup_connect_dot_sslctx(struct daemon* daemon,
|
||||
struct config_file* cfg)
|
||||
{
|
||||
void* ctx;
|
||||
char* bundle, *chroot = daemon->chroot;
|
||||
bundle = cfg->tls_cert_bundle;
|
||||
if(chroot && bundle && strncmp(bundle, chroot, strlen(chroot)) == 0)
|
||||
bundle += strlen(chroot);
|
||||
|
||||
if(!(ctx = connect_sslctx_create(NULL, NULL, bundle,
|
||||
cfg->tls_win_cert))) {
|
||||
log_err("could not set up connect SSL_CTX");
|
||||
return NULL;
|
||||
}
|
||||
return ctx;
|
||||
}
|
||||
#endif /* HAVE_SSL */
|
||||
|
||||
/* setups the needed ssl contexts, fatal_exit() on any failure */
|
||||
void
|
||||
daemon_setup_sslctxs(struct daemon* daemon, struct config_file* cfg)
|
||||
{
|
||||
#ifdef HAVE_SSL
|
||||
char* chroot = daemon->chroot;
|
||||
if(cfg->ssl_service_key && cfg->ssl_service_key[0]) {
|
||||
char* key = cfg->ssl_service_key;
|
||||
char* pem = cfg->ssl_service_pem;
|
||||
if(chroot && strncmp(key, chroot, strlen(chroot)) == 0)
|
||||
key += strlen(chroot);
|
||||
if(chroot && pem && strncmp(pem, chroot, strlen(chroot)) == 0)
|
||||
pem += strlen(chroot);
|
||||
|
||||
/* setup the session keys; the callback to use them will be
|
||||
* attached to each sslctx separately */
|
||||
if(cfg->tls_session_ticket_keys.first &&
|
||||
cfg->tls_session_ticket_keys.first->str[0] != 0) {
|
||||
if(!listen_sslctx_setup_ticket_keys(
|
||||
cfg->tls_session_ticket_keys.first, chroot)) {
|
||||
fatal_exit("could not set session ticket SSL_CTX");
|
||||
}
|
||||
}
|
||||
daemon->listen_dot_sslctx = daemon_setup_listen_dot_sslctx(
|
||||
daemon, cfg);
|
||||
if(!daemon->listen_dot_sslctx)
|
||||
fatal_exit("Could not set up listen dot sslctx");
|
||||
#ifdef HAVE_NGHTTP2_NGHTTP2_H
|
||||
if(cfg_has_https(cfg)) {
|
||||
daemon->listen_doh_sslctx =
|
||||
daemon_setup_listen_doh_sslctx(daemon, cfg);
|
||||
if(!daemon->listen_doh_sslctx)
|
||||
fatal_exit("Could not set up listen doh sslctx");
|
||||
}
|
||||
#endif
|
||||
#ifdef HAVE_NGTCP2
|
||||
if(cfg_has_quic(cfg)) {
|
||||
daemon->listen_quic_sslctx =
|
||||
daemon_setup_listen_quic_sslctx(daemon, cfg);
|
||||
if(!daemon->listen_quic_sslctx)
|
||||
fatal_exit("Could not set up listen quic sslctx");
|
||||
}
|
||||
#endif /* HAVE_NGTCP2 */
|
||||
|
||||
/* Store the file name and mtime to detect changes later. */
|
||||
daemon->ssl_service_key = strdup(cfg->ssl_service_key);
|
||||
if(!daemon->ssl_service_key)
|
||||
fatal_exit("could not setup ssl ctx: out of memory");
|
||||
if(cfg->ssl_service_pem) {
|
||||
daemon->ssl_service_pem = strdup(cfg->ssl_service_pem);
|
||||
if(!daemon->ssl_service_pem)
|
||||
fatal_exit("could not setup ssl ctx: out of memory");
|
||||
} else {
|
||||
daemon->ssl_service_pem = NULL;
|
||||
}
|
||||
if(!file_get_mtime(key,
|
||||
&daemon->mtime_ssl_service_key,
|
||||
&daemon->mtime_ns_ssl_service_key, NULL))
|
||||
log_err("Could not stat(%s): %s",
|
||||
key, strerror(errno));
|
||||
if(pem) {
|
||||
if(!file_get_mtime(pem,
|
||||
&daemon->mtime_ssl_service_pem,
|
||||
&daemon->mtime_ns_ssl_service_pem, NULL))
|
||||
log_err("Could not stat(%s): %s",
|
||||
pem, strerror(errno));
|
||||
} else {
|
||||
daemon->mtime_ssl_service_pem = 0;
|
||||
daemon->mtime_ns_ssl_service_pem = 0;
|
||||
}
|
||||
}
|
||||
daemon->connect_dot_sslctx = daemon_setup_connect_dot_sslctx(
|
||||
daemon, cfg);
|
||||
if(!daemon->connect_dot_sslctx)
|
||||
fatal_exit("could not setup connect dot sslctx");
|
||||
#else /* HAVE_SSL */
|
||||
(void)daemon;(void)cfg;
|
||||
#endif /* HAVE_SSL */
|
||||
}
|
||||
|
||||
/** Delete the ssl ctxs */
|
||||
static void
|
||||
daemon_delete_sslctxs(struct daemon* daemon)
|
||||
{
|
||||
#ifdef HAVE_SSL
|
||||
listen_sslctx_delete_ticket_keys();
|
||||
SSL_CTX_free((SSL_CTX*)daemon->listen_dot_sslctx);
|
||||
daemon->listen_dot_sslctx = NULL;
|
||||
SSL_CTX_free((SSL_CTX*)daemon->listen_doh_sslctx);
|
||||
daemon->listen_doh_sslctx = NULL;
|
||||
SSL_CTX_free((SSL_CTX*)daemon->connect_dot_sslctx);
|
||||
daemon->connect_dot_sslctx = NULL;
|
||||
free(daemon->ssl_service_key);
|
||||
daemon->ssl_service_key = NULL;
|
||||
free(daemon->ssl_service_pem);
|
||||
daemon->ssl_service_pem = NULL;
|
||||
#else
|
||||
(void)daemon;
|
||||
#endif
|
||||
#ifdef HAVE_NGTCP2
|
||||
SSL_CTX_free((SSL_CTX*)daemon->listen_quic_sslctx);
|
||||
daemon->listen_quic_sslctx = NULL;
|
||||
#endif
|
||||
}
|
||||
|
||||
int
|
||||
ssl_cert_changed(struct daemon* daemon, struct config_file* cfg)
|
||||
{
|
||||
time_t mtime = 0;
|
||||
long ns = 0;
|
||||
char* chroot = daemon->chroot;
|
||||
char* key = cfg->ssl_service_key;
|
||||
char* pem = cfg->ssl_service_pem;
|
||||
log_assert(daemon->ssl_service_key && cfg->ssl_service_key);
|
||||
if(chroot && strncmp(key, chroot, strlen(chroot)) == 0)
|
||||
key += strlen(chroot);
|
||||
if(chroot && pem && strncmp(pem, chroot, strlen(chroot)) == 0)
|
||||
pem += strlen(chroot);
|
||||
|
||||
if(strcmp(daemon->ssl_service_key, cfg->ssl_service_key) != 0)
|
||||
return 1;
|
||||
if(daemon->ssl_service_pem && cfg->ssl_service_pem &&
|
||||
strcmp(daemon->ssl_service_pem, cfg->ssl_service_pem) != 0)
|
||||
return 1;
|
||||
if(!file_get_mtime(key, &mtime, &ns, NULL)) {
|
||||
log_err("Could not stat(%s): %s",
|
||||
key, strerror(errno));
|
||||
/* It has probably changed, but file read is likely going to
|
||||
* fail. */
|
||||
return 0;
|
||||
}
|
||||
if(mtime != daemon->mtime_ssl_service_key ||
|
||||
ns != daemon->mtime_ns_ssl_service_key)
|
||||
return 1;
|
||||
if(pem) {
|
||||
if(!file_get_mtime(pem, &mtime, &ns, NULL)) {
|
||||
log_err("Could not stat(%s): %s",
|
||||
pem, strerror(errno));
|
||||
/* It has probably changed, but file read is likely going to
|
||||
* fail. */
|
||||
return 0;
|
||||
}
|
||||
if(mtime != daemon->mtime_ssl_service_pem ||
|
||||
ns != daemon->mtime_ns_ssl_service_pem)
|
||||
return 1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
/** Reload the sslctxs if they have changed */
|
||||
static void
|
||||
daemon_reload_sslctxs(struct daemon* daemon)
|
||||
{
|
||||
#ifdef HAVE_SSL
|
||||
if(daemon->cfg->ssl_service_key && daemon->cfg->ssl_service_key[0]) {
|
||||
/* See if changed */
|
||||
if(!daemon->ssl_service_key ||
|
||||
ssl_cert_changed(daemon,daemon->cfg)) {
|
||||
verbose(VERB_ALGO, "Reloading certificates");
|
||||
daemon_delete_sslctxs(daemon);
|
||||
daemon_setup_sslctxs(daemon, daemon->cfg);
|
||||
}
|
||||
} else {
|
||||
/* See if sslctxs are removed from config. */
|
||||
if(daemon->ssl_service_key) {
|
||||
verbose(VERB_ALGO, "Removing certificates");
|
||||
daemon_delete_sslctxs(daemon);
|
||||
}
|
||||
}
|
||||
#else
|
||||
(void)daemon;
|
||||
#endif
|
||||
}
|
||||
|
||||
struct daemon*
|
||||
daemon_init(void)
|
||||
{
|
||||
@@ -235,7 +497,11 @@ daemon_init(void)
|
||||
# else
|
||||
OPENSSL_init_crypto(OPENSSL_INIT_ADD_ALL_CIPHERS
|
||||
| OPENSSL_INIT_ADD_ALL_DIGESTS
|
||||
| OPENSSL_INIT_LOAD_CRYPTO_STRINGS, NULL);
|
||||
| OPENSSL_INIT_LOAD_CRYPTO_STRINGS
|
||||
# if defined(OPENSSL_INIT_NO_LOAD_CONFIG) && defined(UB_ON_WINDOWS)
|
||||
| OPENSSL_INIT_NO_LOAD_CONFIG
|
||||
# endif
|
||||
, NULL);
|
||||
# endif
|
||||
# if HAVE_DECL_SSL_COMP_GET_COMPRESSION_METHODS
|
||||
/* grab the COMP method ptr because openssl leaks it */
|
||||
@@ -244,7 +510,11 @@ daemon_init(void)
|
||||
# if OPENSSL_VERSION_NUMBER < 0x10100000 || !defined(HAVE_OPENSSL_INIT_SSL)
|
||||
(void)SSL_library_init();
|
||||
# else
|
||||
(void)OPENSSL_init_ssl(OPENSSL_INIT_LOAD_SSL_STRINGS, NULL);
|
||||
(void)OPENSSL_init_ssl(OPENSSL_INIT_LOAD_SSL_STRINGS
|
||||
# if defined(OPENSSL_INIT_NO_LOAD_CONFIG) && defined(UB_ON_WINDOWS)
|
||||
| OPENSSL_INIT_NO_LOAD_CONFIG
|
||||
# endif
|
||||
, NULL);
|
||||
# endif
|
||||
# if defined(HAVE_SSL) && defined(OPENSSL_THREADS) && !defined(THREADS_DISABLED)
|
||||
if(!ub_openssl_lock_init())
|
||||
@@ -556,11 +826,17 @@ daemon_create_workers(struct daemon* daemon)
|
||||
fatal_exit("out of memory during daemon init");
|
||||
numport = daemon_get_shufport(daemon, shufport);
|
||||
verbose(VERB_ALGO, "total of %d outgoing ports available", numport);
|
||||
if(!(daemon->shared_ports = shared_ports_create(daemon->cfg->out_ifs,
|
||||
daemon->cfg->num_out_ifs, daemon->cfg->do_ip4,
|
||||
daemon->cfg->do_ip6, shufport, numport)))
|
||||
fatal_exit("could not setup shared ports: out of memory");
|
||||
|
||||
#ifdef HAVE_NGTCP2
|
||||
daemon->doq_table = doq_table_create(daemon->cfg, daemon->rand);
|
||||
if(!daemon->doq_table)
|
||||
fatal_exit("could not create doq_table: out of memory");
|
||||
if (cfg_has_quic(daemon->cfg)) {
|
||||
daemon->doq_table = doq_table_create(daemon->cfg, daemon->rand);
|
||||
if(!daemon->doq_table)
|
||||
fatal_exit("could not create doq_table: out of memory");
|
||||
}
|
||||
#endif
|
||||
|
||||
daemon->num = (daemon->cfg->num_threads?daemon->cfg->num_threads:1);
|
||||
@@ -584,10 +860,7 @@ daemon_create_workers(struct daemon* daemon)
|
||||
#endif
|
||||
}
|
||||
for(i=0; i<daemon->num; i++) {
|
||||
if(!(daemon->workers[i] = worker_create(daemon, i,
|
||||
shufport+numport*i/daemon->num,
|
||||
numport*(i+1)/daemon->num - numport*i/daemon->num)))
|
||||
/* the above is not ports/numthr, due to rounding */
|
||||
if(!(daemon->workers[i] = worker_create(daemon, i)))
|
||||
fatal_exit("could not create worker");
|
||||
}
|
||||
/* create per-worker alloc caches if not reusing existing ones. */
|
||||
@@ -631,6 +904,25 @@ static void close_other_pipes(struct daemon* daemon, int thr)
|
||||
}
|
||||
#endif /* THREADS_DISABLED */
|
||||
|
||||
/**
|
||||
* Function to set the thread local log ID.
|
||||
* Either the internal thread number, or the LWP ID on Linux based on
|
||||
* configuration.
|
||||
*/
|
||||
static void
|
||||
set_log_thread_id(struct worker* worker, struct config_file* cfg)
|
||||
{
|
||||
(void)cfg;
|
||||
log_assert(worker);
|
||||
#if defined(HAVE_GETTID) && !defined(THREADS_DISABLED)
|
||||
worker->thread_tid = gettid();
|
||||
if(cfg->log_thread_id)
|
||||
log_thread_set(&worker->thread_tid);
|
||||
else
|
||||
#endif
|
||||
log_thread_set(&worker->thread_num);
|
||||
}
|
||||
|
||||
/**
|
||||
* Function to start one thread.
|
||||
* @param arg: user argument.
|
||||
@@ -641,7 +933,15 @@ thread_start(void* arg)
|
||||
{
|
||||
struct worker* worker = (struct worker*)arg;
|
||||
int port_num = 0;
|
||||
log_thread_set(&worker->thread_num);
|
||||
set_log_thread_id(worker, worker->daemon->cfg);
|
||||
{
|
||||
char name[16]; /* seems to be the safest size between
|
||||
different OSes */
|
||||
snprintf(name, sizeof(name), "unbound/%u", worker->thread_num);
|
||||
/* worker->thr_id can be written to after the thread was made
|
||||
* by the creating thread, so this uses pthread_self. */
|
||||
ub_thread_setname(ub_thread_self(), name);
|
||||
}
|
||||
ub_thread_blocksigs();
|
||||
#ifdef THREADS_DISABLED
|
||||
/* close pipe ends used by main */
|
||||
@@ -655,8 +955,9 @@ thread_start(void* arg)
|
||||
port_num = 0;
|
||||
#endif
|
||||
if(!worker_init(worker, worker->daemon->cfg,
|
||||
worker->daemon->ports[port_num], 0))
|
||||
worker->daemon->ports[port_num], 0)) {
|
||||
fatal_exit("Could not initialize thread");
|
||||
}
|
||||
|
||||
worker_work(worker);
|
||||
return NULL;
|
||||
@@ -716,6 +1017,7 @@ daemon_fork(struct daemon* daemon)
|
||||
#endif
|
||||
|
||||
log_assert(daemon);
|
||||
daemon_reload_sslctxs(daemon);
|
||||
if(!(daemon->env->views = views_create()))
|
||||
fatal_exit("Could not create views: out of memory");
|
||||
/* create individual views and their localzone/data trees */
|
||||
@@ -801,14 +1103,25 @@ daemon_fork(struct daemon* daemon)
|
||||
fatal_exit("RPZ requires the respip module");
|
||||
|
||||
/* first create all the worker structures, so we can pass
|
||||
* them to the newly created threads.
|
||||
* them to the newly created threads.
|
||||
*/
|
||||
daemon_create_workers(daemon);
|
||||
/* Set it for the first (main) worker since it does not take part in
|
||||
* the thread_start() procedure.
|
||||
*/
|
||||
set_log_thread_id(daemon->workers[0], daemon->cfg);
|
||||
/* If shm stats need an offset, calculate it */
|
||||
if(daemon->cfg->shm_enable && daemon->cfg->stat_interval > 0) {
|
||||
daemon->stat_time_specific = 1;
|
||||
daemon->stat_time_offset =
|
||||
((int)time(NULL))%daemon->cfg->stat_interval;
|
||||
}
|
||||
|
||||
#if defined(HAVE_EV_LOOP) || defined(HAVE_EV_DEFAULT_LOOP)
|
||||
/* in libev the first inited base gets signals */
|
||||
if(!worker_init(daemon->workers[0], daemon->cfg, daemon->ports[0], 1))
|
||||
if(!worker_init(daemon->workers[0], daemon->cfg, daemon->ports[0], 1)) {
|
||||
fatal_exit("Could not initialize main thread");
|
||||
}
|
||||
#endif
|
||||
|
||||
/* Now create the threads and init the workers.
|
||||
@@ -821,8 +1134,9 @@ daemon_fork(struct daemon* daemon)
|
||||
*/
|
||||
#if !(defined(HAVE_EV_LOOP) || defined(HAVE_EV_DEFAULT_LOOP))
|
||||
/* libevent has the last inited base get signals (or any base) */
|
||||
if(!worker_init(daemon->workers[0], daemon->cfg, daemon->ports[0], 1))
|
||||
if(!worker_init(daemon->workers[0], daemon->cfg, daemon->ports[0], 1)) {
|
||||
fatal_exit("Could not initialize main thread");
|
||||
}
|
||||
#endif
|
||||
signal_handling_playback(daemon->workers[0]);
|
||||
|
||||
@@ -866,7 +1180,6 @@ daemon_cleanup(struct daemon* daemon)
|
||||
/* before stopping main worker, handle signals ourselves, so we
|
||||
don't die on multiple reload signals for example. */
|
||||
signal_handling_record();
|
||||
log_thread_set(NULL);
|
||||
/* clean up caches because
|
||||
* a) RRset IDs will be recycled after a reload, causing collisions
|
||||
* b) validation config can change, thus rrset, msg, keycache clear
|
||||
@@ -908,6 +1221,8 @@ daemon_cleanup(struct daemon* daemon)
|
||||
if(!daemon->reuse_cache || daemon->need_to_exit)
|
||||
daemon_clear_allocs(daemon);
|
||||
daemon->num = 0;
|
||||
shared_ports_delete(daemon->shared_ports);
|
||||
daemon->shared_ports = NULL;
|
||||
#ifdef USE_DNSTAP
|
||||
dt_delete(daemon->dtenv);
|
||||
daemon->dtenv = NULL;
|
||||
@@ -917,8 +1232,10 @@ daemon_cleanup(struct daemon* daemon)
|
||||
daemon->dnscenv = NULL;
|
||||
#endif
|
||||
#ifdef HAVE_NGTCP2
|
||||
doq_table_delete(daemon->doq_table);
|
||||
daemon->doq_table = NULL;
|
||||
if (daemon->doq_table) {
|
||||
doq_table_delete(daemon->doq_table);
|
||||
daemon->doq_table = NULL;
|
||||
}
|
||||
#endif
|
||||
daemon->cfg = NULL;
|
||||
}
|
||||
@@ -956,15 +1273,7 @@ daemon_delete(struct daemon* daemon)
|
||||
free(daemon->pidfile);
|
||||
free(daemon->cfgfile);
|
||||
free(daemon->env);
|
||||
#ifdef HAVE_SSL
|
||||
listen_sslctx_delete_ticket_keys();
|
||||
SSL_CTX_free((SSL_CTX*)daemon->listen_dot_sslctx);
|
||||
SSL_CTX_free((SSL_CTX*)daemon->listen_doh_sslctx);
|
||||
SSL_CTX_free((SSL_CTX*)daemon->connect_dot_sslctx);
|
||||
#endif
|
||||
#ifdef HAVE_NGTCP2
|
||||
SSL_CTX_free((SSL_CTX*)daemon->listen_quic_sslctx);
|
||||
#endif
|
||||
daemon_delete_sslctxs(daemon);
|
||||
free(daemon);
|
||||
/* lex cleanup */
|
||||
ub_c_lex_destroy();
|
||||
@@ -976,7 +1285,7 @@ daemon_delete(struct daemon* daemon)
|
||||
# if HAVE_DECL_SSL_COMP_GET_COMPRESSION_METHODS && HAVE_DECL_SK_SSL_COMP_POP_FREE
|
||||
# ifndef S_SPLINT_S
|
||||
# if OPENSSL_VERSION_NUMBER < 0x10100000
|
||||
sk_SSL_COMP_pop_free(comp_meth, (void(*)())CRYPTO_free);
|
||||
sk_SSL_COMP_pop_free(comp_meth, (void(*)(SSL_COMP*))CRYPTO_free);
|
||||
# endif
|
||||
# endif
|
||||
# endif
|
||||
@@ -999,6 +1308,9 @@ daemon_delete(struct daemon* daemon)
|
||||
# if defined(HAVE_SSL) && defined(OPENSSL_THREADS) && !defined(THREADS_DISABLED)
|
||||
ub_openssl_lock_delete();
|
||||
# endif
|
||||
#ifdef HAVE_OPENSSL_CLEANUP
|
||||
OPENSSL_cleanup();
|
||||
#endif
|
||||
#ifndef HAVE_ARC4RANDOM
|
||||
_ARC4_LOCK_DESTROY();
|
||||
#endif
|
||||
|
||||
@@ -62,6 +62,7 @@ struct doq_table;
|
||||
struct cookie_secrets;
|
||||
struct fast_reload_thread;
|
||||
struct fast_reload_printq;
|
||||
struct shared_ports;
|
||||
|
||||
#include "dnstap/dnstap_config.h"
|
||||
#ifdef USE_DNSTAP
|
||||
@@ -97,6 +98,8 @@ struct daemon {
|
||||
int rc_port;
|
||||
/** listening ports for remote control */
|
||||
struct listen_port* rc_ports;
|
||||
/** the shared ports structure, with random ports numbers. */
|
||||
struct shared_ports* shared_ports;
|
||||
/** remote control connections management (for first worker) */
|
||||
struct daemon_remote* rc;
|
||||
/** ssl context for listening to dnstcp over ssl */
|
||||
@@ -107,6 +110,18 @@ struct daemon {
|
||||
void* listen_doh_sslctx;
|
||||
/** ssl context for listening to quic */
|
||||
void* listen_quic_sslctx;
|
||||
/** the file name that the ssl context is made with, private key. */
|
||||
char* ssl_service_key;
|
||||
/** the file name that the ssl context is made with, certificate. */
|
||||
char* ssl_service_pem;
|
||||
/** modification time for ssl_service_key, in sec and ns. Like
|
||||
* in a struct timespec, but without that for portability. */
|
||||
time_t mtime_ssl_service_key;
|
||||
long mtime_ns_ssl_service_key;
|
||||
/** modification time for ssl_service_pem, in sec and ns. Like
|
||||
* in a struct timespec, but without that for portability. */
|
||||
time_t mtime_ssl_service_pem;
|
||||
long mtime_ns_ssl_service_pem;
|
||||
/** num threads allocated */
|
||||
int num;
|
||||
/** num threads allocated in the previous config or 0 at first */
|
||||
@@ -143,7 +158,14 @@ struct daemon {
|
||||
/** the dnstap environment master value, copied and changed by threads*/
|
||||
struct dt_env* dtenv;
|
||||
#endif
|
||||
/** The SHM info for shared memory stats. */
|
||||
struct shm_main_info* shm_info;
|
||||
/** if the timeout for statistics is attempted at specific offset.
|
||||
* If it is true, the stat timeout is the interval+offset, and that
|
||||
* picks (roughly) the same time offset every time period. */
|
||||
int stat_time_specific;
|
||||
/** if the timeout is specific, what offset in the period. */
|
||||
int stat_time_offset;
|
||||
/** some response-ip tags or actions are configured if true */
|
||||
int use_response_ip;
|
||||
/** some RPZ policies are configured */
|
||||
@@ -229,4 +251,26 @@ void daemon_apply_cfg(struct daemon* daemon, struct config_file* cfg);
|
||||
*/
|
||||
int setup_acl_for_ports(struct acl_list* list, struct listen_port* port_list);
|
||||
|
||||
/* setups the needed ssl contexts, fatal_exit() on any failure */
|
||||
void daemon_setup_sslctxs(struct daemon* daemon, struct config_file* cfg);
|
||||
|
||||
/** See if the SSL cert files have changed */
|
||||
int ssl_cert_changed(struct daemon* daemon, struct config_file* cfg);
|
||||
|
||||
/** Setup the listening DoT SSL_CTX, returns the ssl ctx. */
|
||||
void* daemon_setup_listen_dot_sslctx(struct daemon* daemon,
|
||||
struct config_file* cfg);
|
||||
|
||||
/** Setup the listening DoH SSL_CTX, returns the ssl ctx. */
|
||||
void* daemon_setup_listen_doh_sslctx(struct daemon* daemon,
|
||||
struct config_file* cfg);
|
||||
|
||||
/** Setup the listening Quic SSL_CTX, returns the ssl ctx */
|
||||
void* daemon_setup_listen_quic_sslctx(struct daemon* daemon,
|
||||
struct config_file* cfg);
|
||||
|
||||
/** Setup the connect DoT SSL_CTX, returns the ssl ctx */
|
||||
void* daemon_setup_connect_dot_sslctx(struct daemon* daemon,
|
||||
struct config_file* cfg);
|
||||
|
||||
#endif /* DAEMON_H */
|
||||
|
||||
+1155
-222
File diff suppressed because it is too large
Load Diff
+9
-7
@@ -49,6 +49,7 @@
|
||||
#include <openssl/ssl.h>
|
||||
#endif
|
||||
#include "util/locks.h"
|
||||
#include "libunbound/remote.h"
|
||||
struct config_file;
|
||||
struct listen_list;
|
||||
struct listen_port;
|
||||
@@ -206,6 +207,12 @@ struct fast_reload_thread {
|
||||
int commpair[2];
|
||||
/** thread id, of the io thread */
|
||||
ub_thread_type tid;
|
||||
#ifdef HAVE_GETTID
|
||||
/** thread tid, the LWP id */
|
||||
pid_t thread_tid;
|
||||
/** if logging should include the LWP id */
|
||||
int thread_tid_log;
|
||||
#endif
|
||||
/** if the io processing has started */
|
||||
int started;
|
||||
/** if the thread has to quit */
|
||||
@@ -249,6 +256,8 @@ struct fast_reload_thread {
|
||||
struct fast_reload_auth_change* auth_zone_change_list;
|
||||
/** the old tree of auth zones, to lookup. */
|
||||
struct auth_zones* old_auth_zones;
|
||||
/** If the ssl ctxs have changed. */
|
||||
int sslctxs_changed;
|
||||
};
|
||||
|
||||
/**
|
||||
@@ -357,13 +366,6 @@ void fast_reload_thread_start(RES* ssl, struct worker* worker,
|
||||
*/
|
||||
void fast_reload_thread_stop(struct fast_reload_thread* fast_reload_thread);
|
||||
|
||||
/** fast reload thread commands to remote service thread event callback */
|
||||
void fast_reload_service_cb(int fd, short bits, void* arg);
|
||||
|
||||
/** fast reload callback for the remote control client connection */
|
||||
int fast_reload_client_callback(struct comm_point* c, void* arg, int err,
|
||||
struct comm_reply* rep);
|
||||
|
||||
/** fast reload printq delete list */
|
||||
void fast_reload_printq_list_delete(struct fast_reload_printq* list);
|
||||
|
||||
|
||||
+30
-6
@@ -262,6 +262,7 @@ server_stats_compile(struct worker* worker, struct ub_stats_info* s, int reset)
|
||||
s->svr = worker->stats;
|
||||
s->mesh_num_states = (long long)worker->env.mesh->all.count;
|
||||
s->mesh_num_reply_states = (long long)worker->env.mesh->num_reply_states;
|
||||
s->mesh_num_reply_addrs = (long long)worker->env.mesh->num_reply_addrs;
|
||||
s->mesh_jostled = (long long)worker->env.mesh->stats_jostled;
|
||||
s->mesh_dropped = (long long)worker->env.mesh->stats_dropped;
|
||||
s->mesh_replies_sent = (long long)worker->env.mesh->replies_sent;
|
||||
@@ -273,6 +274,7 @@ server_stats_compile(struct worker* worker, struct ub_stats_info* s, int reset)
|
||||
/* add in the values from the mesh */
|
||||
s->svr.ans_secure += (long long)worker->env.mesh->ans_secure;
|
||||
s->svr.ans_bogus += (long long)worker->env.mesh->ans_bogus;
|
||||
s->svr.val_ops += (long long)worker->env.mesh->val_ops;
|
||||
s->svr.ans_rcode_nodata += (long long)worker->env.mesh->ans_nodata;
|
||||
s->svr.ans_expired += (long long)worker->env.mesh->ans_expired;
|
||||
for(i=0; i<UB_STATS_RCODE_NUM; i++)
|
||||
@@ -283,6 +285,8 @@ server_stats_compile(struct worker* worker, struct ub_stats_info* s, int reset)
|
||||
NUM_BUCKETS_HIST);
|
||||
s->svr.num_queries_discard_timeout +=
|
||||
(long long)worker->env.mesh->num_queries_discard_timeout;
|
||||
s->svr.num_queries_replyaddr_limit +=
|
||||
(long long)worker->env.mesh->num_queries_replyaddr_limit;
|
||||
s->svr.num_queries_wait_limit +=
|
||||
(long long)worker->env.mesh->num_queries_wait_limit;
|
||||
s->svr.num_dns_error_reports +=
|
||||
@@ -418,12 +422,28 @@ void server_stats_obtain(struct worker* worker, struct worker* who,
|
||||
# endif
|
||||
#endif
|
||||
);
|
||||
log_err("server_stats_obtain: no response from worker %d "
|
||||
"(stats timeout); returning zero stats for this worker",
|
||||
who->thread_num);
|
||||
/* A later reply from the worker, would be sizeof stats reply,
|
||||
* and the worker_handle_control_cmd routine discards if
|
||||
* it is not a 4byte command, when that is received here. */
|
||||
memset(s, 0, sizeof(*s));
|
||||
return;
|
||||
}
|
||||
if(!tube_read_msg(worker->cmd, &reply, &len, 0)) {
|
||||
log_err("server_stats_obtain: failed to read stats from worker "
|
||||
"(tube read error); returning zero stats for this worker");
|
||||
memset(s, 0, sizeof(*s));
|
||||
return;
|
||||
}
|
||||
if(len != (uint32_t)sizeof(*s)) {
|
||||
log_err("server_stats_obtain: wrong stats length %d (expected %d); "
|
||||
"discarding", (int)len, (int)sizeof(*s));
|
||||
free(reply);
|
||||
memset(s, 0, sizeof(*s));
|
||||
return;
|
||||
}
|
||||
if(!tube_read_msg(worker->cmd, &reply, &len, 0))
|
||||
fatal_exit("failed to read stats over cmd channel");
|
||||
if(len != (uint32_t)sizeof(*s))
|
||||
fatal_exit("stats on cmd channel wrong length %d %d",
|
||||
(int)len, (int)sizeof(*s));
|
||||
memcpy(s, reply, (size_t)len);
|
||||
free(reply);
|
||||
}
|
||||
@@ -435,7 +455,7 @@ void server_stats_reply(struct worker* worker, int reset)
|
||||
verbose(VERB_ALGO, "write stats replymsg");
|
||||
if(!tube_write_msg(worker->daemon->workers[0]->cmd,
|
||||
(uint8_t*)&s, sizeof(s), 0))
|
||||
fatal_exit("could not write stat values over cmd channel");
|
||||
log_err("could not write stat values over cmd channel");
|
||||
}
|
||||
|
||||
void server_stats_add(struct ub_stats_info* total, struct ub_stats_info* a)
|
||||
@@ -447,6 +467,8 @@ void server_stats_add(struct ub_stats_info* total, struct ub_stats_info* a)
|
||||
total->svr.num_queries_cookie_invalid += a->svr.num_queries_cookie_invalid;
|
||||
total->svr.num_queries_discard_timeout +=
|
||||
a->svr.num_queries_discard_timeout;
|
||||
total->svr.num_queries_replyaddr_limit +=
|
||||
a->svr.num_queries_replyaddr_limit;
|
||||
total->svr.num_queries_wait_limit += a->svr.num_queries_wait_limit;
|
||||
total->svr.num_dns_error_reports += a->svr.num_dns_error_reports;
|
||||
total->svr.num_queries_missed_cache += a->svr.num_queries_missed_cache;
|
||||
@@ -495,6 +517,7 @@ void server_stats_add(struct ub_stats_info* total, struct ub_stats_info* a)
|
||||
total->svr.ans_rcode_nodata += a->svr.ans_rcode_nodata;
|
||||
total->svr.ans_secure += a->svr.ans_secure;
|
||||
total->svr.ans_bogus += a->svr.ans_bogus;
|
||||
total->svr.val_ops += a->svr.val_ops;
|
||||
total->svr.unwanted_replies += a->svr.unwanted_replies;
|
||||
total->svr.unwanted_queries += a->svr.unwanted_queries;
|
||||
total->svr.tcp_accept_usage += a->svr.tcp_accept_usage;
|
||||
@@ -517,6 +540,7 @@ void server_stats_add(struct ub_stats_info* total, struct ub_stats_info* a)
|
||||
|
||||
total->mesh_num_states += a->mesh_num_states;
|
||||
total->mesh_num_reply_states += a->mesh_num_reply_states;
|
||||
total->mesh_num_reply_addrs += a->mesh_num_reply_addrs;
|
||||
total->mesh_jostled += a->mesh_jostled;
|
||||
total->mesh_dropped += a->mesh_dropped;
|
||||
total->mesh_replies_sent += a->mesh_replies_sent;
|
||||
|
||||
+6
-50
@@ -174,7 +174,7 @@ static void
|
||||
checkrlimits(struct config_file* cfg)
|
||||
{
|
||||
#ifndef S_SPLINT_S
|
||||
#ifdef HAVE_GETRLIMIT
|
||||
#if defined(HAVE_GETRLIMIT) && !defined(unbound_testbound)
|
||||
/* list has number of ports to listen to, ifs number addresses */
|
||||
int list = ((cfg->do_udp?1:0) + (cfg->do_tcp?1 +
|
||||
(int)cfg->incoming_num_tcp:0));
|
||||
@@ -463,59 +463,13 @@ detach(void)
|
||||
#endif /* HAVE_DAEMON */
|
||||
}
|
||||
|
||||
/* setup a listening ssl context, fatal_exit() on any failure */
|
||||
/** setup the remote and ticket keys */
|
||||
static void
|
||||
setup_listen_sslctx(void** ctx, int is_dot, int is_doh, struct config_file* cfg)
|
||||
{
|
||||
#ifdef HAVE_SSL
|
||||
if(!(*ctx = listen_sslctx_create(
|
||||
cfg->ssl_service_key, cfg->ssl_service_pem, NULL,
|
||||
cfg->tls_ciphers, cfg->tls_ciphersuites,
|
||||
(cfg->tls_session_ticket_keys.first &&
|
||||
cfg->tls_session_ticket_keys.first->str[0] != 0),
|
||||
is_dot, is_doh))) {
|
||||
fatal_exit("could not set up listen SSL_CTX");
|
||||
}
|
||||
#else /* HAVE_SSL */
|
||||
(void)ctx;(void)is_dot;(void)is_doh;(void)cfg;
|
||||
#endif /* HAVE_SSL */
|
||||
}
|
||||
|
||||
/* setups the needed ssl contexts, fatal_exit() on any failure */
|
||||
static void
|
||||
setup_sslctxs(struct daemon* daemon, struct config_file* cfg)
|
||||
setup_sslctx_remote(struct daemon* daemon, struct config_file* cfg)
|
||||
{
|
||||
#ifdef HAVE_SSL
|
||||
if(!(daemon->rc = daemon_remote_create(cfg)))
|
||||
fatal_exit("could not set up remote-control");
|
||||
if(cfg->ssl_service_key && cfg->ssl_service_key[0]) {
|
||||
/* setup the session keys; the callback to use them will be
|
||||
* attached to each sslctx separately */
|
||||
if(cfg->tls_session_ticket_keys.first &&
|
||||
cfg->tls_session_ticket_keys.first->str[0] != 0) {
|
||||
if(!listen_sslctx_setup_ticket_keys(
|
||||
cfg->tls_session_ticket_keys.first)) {
|
||||
fatal_exit("could not set session ticket SSL_CTX");
|
||||
}
|
||||
}
|
||||
(void)setup_listen_sslctx(&daemon->listen_dot_sslctx, 1, 0, cfg);
|
||||
#ifdef HAVE_NGHTTP2_NGHTTP2_H
|
||||
if(cfg_has_https(cfg)) {
|
||||
(void)setup_listen_sslctx(&daemon->listen_doh_sslctx, 0, 1, cfg);
|
||||
}
|
||||
#endif
|
||||
#ifdef HAVE_NGTCP2
|
||||
if(cfg_has_quic(cfg)) {
|
||||
if(!(daemon->listen_quic_sslctx = quic_sslctx_create(
|
||||
cfg->ssl_service_key, cfg->ssl_service_pem, NULL))) {
|
||||
fatal_exit("could not set up quic SSL_CTX");
|
||||
}
|
||||
}
|
||||
#endif /* HAVE_NGTCP2 */
|
||||
}
|
||||
if(!(daemon->connect_dot_sslctx = connect_sslctx_create(NULL, NULL,
|
||||
cfg->tls_cert_bundle, cfg->tls_win_cert)))
|
||||
fatal_exit("could not set up connect SSL_CTX");
|
||||
#else /* HAVE_SSL */
|
||||
(void)daemon;(void)cfg;
|
||||
#endif /* HAVE_SSL */
|
||||
@@ -547,7 +501,8 @@ perform_setup(struct daemon* daemon, struct config_file* cfg, int debug_mode,
|
||||
#endif
|
||||
|
||||
/* read ssl keys while superuser and outside chroot */
|
||||
(void)setup_sslctxs(daemon, cfg);
|
||||
setup_sslctx_remote(daemon, cfg);
|
||||
daemon_setup_sslctxs(daemon, cfg);
|
||||
|
||||
/* init syslog (as root) if needed, before daemonize, otherwise
|
||||
* a fork error could not be printed since daemonize closed stderr.*/
|
||||
@@ -747,6 +702,7 @@ run_daemon(const char* cfgfile, int cmdline_verbose, int debug_mode, int need_pi
|
||||
"the commandline to see more errors, "
|
||||
"or unbound-checkconf", cfgfile);
|
||||
log_warn("Continuing with default config settings");
|
||||
config_auto_slab_values(cfg);
|
||||
}
|
||||
apply_settings(daemon, cfg, cmdline_verbose, debug_mode);
|
||||
if(!done_setup)
|
||||
|
||||
+219
-129
@@ -255,7 +255,8 @@ worker_handle_service_reply(struct comm_point* c, void* arg, int error,
|
||||
return 0;
|
||||
}
|
||||
/* sanity check. */
|
||||
if(!LDNS_QR_WIRE(sldns_buffer_begin(c->buffer))
|
||||
if(sldns_buffer_limit(c->buffer) < LDNS_HEADER_SIZE
|
||||
|| !LDNS_QR_WIRE(sldns_buffer_begin(c->buffer))
|
||||
|| LDNS_OPCODE_WIRE(sldns_buffer_begin(c->buffer)) !=
|
||||
LDNS_PACKET_QUERY
|
||||
|| LDNS_QDCOUNT(sldns_buffer_begin(c->buffer)) > 1) {
|
||||
@@ -292,6 +293,44 @@ worker_err_ratelimit(struct worker* worker, int err)
|
||||
return err;
|
||||
}
|
||||
|
||||
/**
|
||||
* Reply with an error.
|
||||
* This reply includes the qname if it has been parsed.
|
||||
* For error ratelimiting, the err ratelimit routine should be checked
|
||||
* beforehand. The reply is without EDNS, and copies RD and sets QR flag.
|
||||
* @param pkt: the packet buffer from the comm point.
|
||||
* @param err: the error code that would be wanted.
|
||||
* @param qname_len: 0 if not parsed, and the qname length in packet.
|
||||
*/
|
||||
static void
|
||||
query_error(sldns_buffer* pkt, int err, size_t qname_len)
|
||||
{
|
||||
/* Preserve the RD flag.
|
||||
* The CD flag must be cleared in authoritative answers,
|
||||
* also the AD flag need not be copied into answers.
|
||||
* The other flags need not be copied into the answer. */
|
||||
sldns_buffer_write_u16_at(pkt, 2,
|
||||
sldns_buffer_read_u16_at(pkt, 2)&0x0100U);
|
||||
LDNS_QR_SET(sldns_buffer_begin(pkt)); /* Set QR flag. */
|
||||
LDNS_RCODE_SET(sldns_buffer_begin(pkt), err); /* Set rcode */
|
||||
|
||||
if(qname_len && LDNS_QDCOUNT(sldns_buffer_begin(pkt))>=1 &&
|
||||
qname_len <= LDNS_MAX_DOMAINLEN) {
|
||||
/* Copy query into the answer. */
|
||||
LDNS_QDCOUNT_SET(sldns_buffer_begin(pkt), 1);
|
||||
sldns_buffer_set_position(pkt, LDNS_HEADER_SIZE +
|
||||
qname_len + 2 /* type */ + 2 /* class */ );
|
||||
} else {
|
||||
/* No query section in answer. */
|
||||
LDNS_QDCOUNT_SET(sldns_buffer_begin(pkt), 0);
|
||||
sldns_buffer_set_position(pkt, LDNS_HEADER_SIZE);
|
||||
}
|
||||
LDNS_ANCOUNT_SET(sldns_buffer_begin(pkt), 0);
|
||||
LDNS_NSCOUNT_SET(sldns_buffer_begin(pkt), 0);
|
||||
LDNS_ARCOUNT_SET(sldns_buffer_begin(pkt), 0);
|
||||
sldns_buffer_flip(pkt);
|
||||
}
|
||||
|
||||
/**
|
||||
* Structure holding the result of the worker_check_request function.
|
||||
* Based on configuration it could be called up to four times; ideally should
|
||||
@@ -329,7 +368,6 @@ worker_check_request(sldns_buffer* pkt, struct worker* worker,
|
||||
return;
|
||||
}
|
||||
if(LDNS_TC_WIRE(sldns_buffer_begin(pkt))) {
|
||||
LDNS_TC_CLR(sldns_buffer_begin(pkt));
|
||||
verbose(VERB_QUERY, "request bad, has TC bit on");
|
||||
out->value = worker_err_ratelimit(worker, LDNS_RCODE_FORMERR);
|
||||
return;
|
||||
@@ -463,7 +501,9 @@ worker_handle_control_cmd(struct tube* ATTR_UNUSED(tube), uint8_t* msg,
|
||||
return;
|
||||
}
|
||||
if(len != sizeof(uint32_t)) {
|
||||
fatal_exit("bad control msg length %d", (int)len);
|
||||
verbose(VERB_ALGO, "bad control msg length %d", (int)len);
|
||||
free(msg);
|
||||
return;
|
||||
}
|
||||
cmd = sldns_read_uint32(msg);
|
||||
free(msg);
|
||||
@@ -676,7 +716,8 @@ apply_respip_action(struct worker* worker, const struct query_info* qinfo,
|
||||
struct respip_client_info* cinfo, struct reply_info* rep,
|
||||
struct sockaddr_storage* addr, socklen_t addrlen,
|
||||
struct ub_packed_rrset_key** alias_rrset,
|
||||
struct reply_info** encode_repp, struct auth_zones* az)
|
||||
struct reply_info** encode_repp, struct auth_zones* az,
|
||||
int* rpz_passthru)
|
||||
{
|
||||
struct respip_action_info actinfo = {0, 0, 0, 0, NULL, 0, NULL};
|
||||
actinfo.action = respip_none;
|
||||
@@ -687,7 +728,7 @@ apply_respip_action(struct worker* worker, const struct query_info* qinfo,
|
||||
return 1;
|
||||
|
||||
if(!respip_rewrite_reply(qinfo, cinfo, rep, encode_repp, &actinfo,
|
||||
alias_rrset, 0, worker->scratchpad, az, NULL,
|
||||
alias_rrset, 0, worker->scratchpad, az, rpz_passthru,
|
||||
worker->env.views, worker->env.respip_set))
|
||||
return 0;
|
||||
|
||||
@@ -734,7 +775,7 @@ answer_from_cache(struct worker* worker, struct query_info* qinfo,
|
||||
int* is_secure_answer, struct ub_packed_rrset_key** alias_rrset,
|
||||
struct reply_info** partial_repp,
|
||||
struct reply_info* rep, uint16_t id, uint16_t flags,
|
||||
struct comm_reply* repinfo, struct edns_data* edns)
|
||||
struct comm_reply* repinfo, struct edns_data* edns, int* rpz_passthru)
|
||||
{
|
||||
time_t timenow = *worker->env.now;
|
||||
uint16_t udpsize = edns->udp_size;
|
||||
@@ -746,7 +787,7 @@ answer_from_cache(struct worker* worker, struct query_info* qinfo,
|
||||
*partial_repp = NULL; /* avoid accidental further pass */
|
||||
|
||||
/* Check TTL */
|
||||
if(rep->ttl < timenow) {
|
||||
if(TTL_IS_EXPIRED(rep->ttl, timenow)) {
|
||||
/* Check if we need to serve expired now */
|
||||
if(worker->env.cfg->serve_expired &&
|
||||
/* if serve-expired-client-timeout is set, serve
|
||||
@@ -844,7 +885,7 @@ answer_from_cache(struct worker* worker, struct query_info* qinfo,
|
||||
if((worker->daemon->use_response_ip || worker->daemon->use_rpz) &&
|
||||
!partial_rep && !apply_respip_action(worker, qinfo, cinfo, rep,
|
||||
&repinfo->client_addr, repinfo->client_addrlen, alias_rrset,
|
||||
&encode_rep, worker->env.auth_zones)) {
|
||||
&encode_rep, worker->env.auth_zones, rpz_passthru)) {
|
||||
goto bail_out;
|
||||
} else if(partial_rep &&
|
||||
!respip_merge_cname(partial_rep, qinfo, rep, cinfo,
|
||||
@@ -971,6 +1012,7 @@ chaos_replystr(sldns_buffer* pkt, char** str, int num, struct edns_data* edns,
|
||||
size_t udpsize = edns->udp_size;
|
||||
edns->edns_version = EDNS_ADVERTISED_VERSION;
|
||||
edns->udp_size = EDNS_ADVERTISED_SIZE;
|
||||
edns->ext_rcode = 0;
|
||||
edns->bits &= EDNS_DO;
|
||||
if(!inplace_cb_reply_local_call(&worker->env, NULL, NULL, NULL,
|
||||
LDNS_RCODE_NOERROR, edns, repinfo, worker->scratchpad,
|
||||
@@ -1229,9 +1271,7 @@ deny_refuse(struct comm_point* c, enum acl_access acl,
|
||||
worker_check_request(c->buffer, worker, check_result);
|
||||
if(check_result->value != 0) {
|
||||
if(check_result->value != -1) {
|
||||
LDNS_QR_SET(sldns_buffer_begin(c->buffer));
|
||||
LDNS_RCODE_SET(sldns_buffer_begin(c->buffer),
|
||||
check_result->value);
|
||||
query_error(c->buffer, check_result->value, 0);
|
||||
return 1;
|
||||
}
|
||||
comm_point_drop_reply(repinfo);
|
||||
@@ -1248,41 +1288,17 @@ deny_refuse(struct comm_point* c, enum acl_access acl,
|
||||
/* check additional section is present and that we respond with EDEs */
|
||||
if(LDNS_ARCOUNT(sldns_buffer_begin(c->buffer)) != 1
|
||||
|| !ede) {
|
||||
LDNS_QDCOUNT_SET(sldns_buffer_begin(c->buffer), 0);
|
||||
LDNS_ANCOUNT_SET(sldns_buffer_begin(c->buffer), 0);
|
||||
LDNS_NSCOUNT_SET(sldns_buffer_begin(c->buffer), 0);
|
||||
LDNS_ARCOUNT_SET(sldns_buffer_begin(c->buffer), 0);
|
||||
LDNS_QR_SET(sldns_buffer_begin(c->buffer));
|
||||
LDNS_RCODE_SET(sldns_buffer_begin(c->buffer),
|
||||
LDNS_RCODE_REFUSED);
|
||||
sldns_buffer_set_position(c->buffer, LDNS_HEADER_SIZE);
|
||||
sldns_buffer_flip(c->buffer);
|
||||
query_error(c->buffer, LDNS_RCODE_REFUSED, 0);
|
||||
return 1;
|
||||
}
|
||||
|
||||
if (!query_dname_len(c->buffer)) {
|
||||
LDNS_QDCOUNT_SET(sldns_buffer_begin(c->buffer), 0);
|
||||
LDNS_ANCOUNT_SET(sldns_buffer_begin(c->buffer), 0);
|
||||
LDNS_NSCOUNT_SET(sldns_buffer_begin(c->buffer), 0);
|
||||
LDNS_ARCOUNT_SET(sldns_buffer_begin(c->buffer), 0);
|
||||
LDNS_QR_SET(sldns_buffer_begin(c->buffer));
|
||||
LDNS_RCODE_SET(sldns_buffer_begin(c->buffer),
|
||||
LDNS_RCODE_FORMERR);
|
||||
sldns_buffer_set_position(c->buffer, LDNS_HEADER_SIZE);
|
||||
sldns_buffer_flip(c->buffer);
|
||||
query_error(c->buffer, LDNS_RCODE_FORMERR, 0);
|
||||
return 1;
|
||||
}
|
||||
/* space available for query type and class? */
|
||||
if (sldns_buffer_remaining(c->buffer) < 2 * sizeof(uint16_t)) {
|
||||
LDNS_QR_SET(sldns_buffer_begin(c->buffer));
|
||||
LDNS_RCODE_SET(sldns_buffer_begin(c->buffer),
|
||||
LDNS_RCODE_FORMERR);
|
||||
LDNS_QDCOUNT_SET(sldns_buffer_begin(c->buffer), 0);
|
||||
LDNS_ANCOUNT_SET(sldns_buffer_begin(c->buffer), 0);
|
||||
LDNS_NSCOUNT_SET(sldns_buffer_begin(c->buffer), 0);
|
||||
LDNS_ARCOUNT_SET(sldns_buffer_begin(c->buffer), 0);
|
||||
sldns_buffer_set_position(c->buffer, LDNS_HEADER_SIZE);
|
||||
sldns_buffer_flip(c->buffer);
|
||||
query_error(c->buffer, LDNS_RCODE_FORMERR, 0);
|
||||
return 1;
|
||||
}
|
||||
LDNS_QR_SET(sldns_buffer_begin(c->buffer));
|
||||
@@ -1304,35 +1320,27 @@ deny_refuse(struct comm_point* c, enum acl_access acl,
|
||||
if(!skip_pkt_rrs(c->buffer,
|
||||
((int)LDNS_ANCOUNT(sldns_buffer_begin(c->buffer)))+
|
||||
((int)LDNS_NSCOUNT(sldns_buffer_begin(c->buffer))))) {
|
||||
LDNS_RCODE_SET(sldns_buffer_begin(c->buffer),
|
||||
LDNS_RCODE_FORMERR);
|
||||
LDNS_ANCOUNT_SET(sldns_buffer_begin(c->buffer), 0);
|
||||
LDNS_NSCOUNT_SET(sldns_buffer_begin(c->buffer), 0);
|
||||
LDNS_ARCOUNT_SET(sldns_buffer_begin(c->buffer), 0);
|
||||
sldns_buffer_set_position(c->buffer, opt_rr_mark);
|
||||
sldns_buffer_flip(c->buffer);
|
||||
query_error(c->buffer, LDNS_RCODE_FORMERR,
|
||||
opt_rr_mark - LDNS_HEADER_SIZE
|
||||
- 2 /* qtype */ - 2 /* qclass */);
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
/* Do we have a valid OPT RR here? If not return REFUSED (could be a valid TSIG or something so no FORMERR) */
|
||||
/* domain name must be the root of length 1. */
|
||||
if(sldns_buffer_remaining(c->buffer) < 1 || *sldns_buffer_current(c->buffer) != 0) {
|
||||
LDNS_ANCOUNT_SET(sldns_buffer_begin(c->buffer), 0);
|
||||
LDNS_NSCOUNT_SET(sldns_buffer_begin(c->buffer), 0);
|
||||
LDNS_ARCOUNT_SET(sldns_buffer_begin(c->buffer), 0);
|
||||
sldns_buffer_set_position(c->buffer, opt_rr_mark);
|
||||
sldns_buffer_flip(c->buffer);
|
||||
query_error(c->buffer, LDNS_RCODE_REFUSED,
|
||||
opt_rr_mark - LDNS_HEADER_SIZE
|
||||
- 2 /* qtype */ - 2 /* qclass */);
|
||||
return 1;
|
||||
} else {
|
||||
sldns_buffer_skip(c->buffer, 1); /* skip root label */
|
||||
}
|
||||
if(sldns_buffer_remaining(c->buffer) < 2 ||
|
||||
sldns_buffer_read_u16(c->buffer) != LDNS_RR_TYPE_OPT) {
|
||||
LDNS_ANCOUNT_SET(sldns_buffer_begin(c->buffer), 0);
|
||||
LDNS_NSCOUNT_SET(sldns_buffer_begin(c->buffer), 0);
|
||||
LDNS_ARCOUNT_SET(sldns_buffer_begin(c->buffer), 0);
|
||||
sldns_buffer_set_position(c->buffer, opt_rr_mark);
|
||||
sldns_buffer_flip(c->buffer);
|
||||
query_error(c->buffer, LDNS_RCODE_REFUSED,
|
||||
opt_rr_mark - LDNS_HEADER_SIZE
|
||||
- 2 /* qtype */ - 2 /* qclass */);
|
||||
return 1;
|
||||
}
|
||||
/* Write OPT RR directly after the query,
|
||||
@@ -1444,6 +1452,24 @@ check_ip_ratelimit(struct worker* worker, struct sockaddr_storage* addr,
|
||||
return 1;
|
||||
}
|
||||
|
||||
/*
|
||||
* This is the callback function when a request arrives. It is passed
|
||||
* the packet and user argument. Return true to send a reply.
|
||||
* This is of type comm_point_callback_type. The struct comm_point contains
|
||||
* more comments on the comm_point.callback member about the function.
|
||||
* @param c: the comm_point where the request arrives on.
|
||||
* @param arg: the user argument for the callback, the worker.
|
||||
* @param error: This can be NETEVENT_NOERROR, NETEVENT_TIMEOUT,
|
||||
* NETEVENT_CLOSED or other comm point callback error values.
|
||||
* @param repinfo: The reply info, use it to send a reply. If the reply
|
||||
* is immediate, return 1. If the reply is later on return 0 and save
|
||||
* the repinfo, to call comm_point_send_reply on.
|
||||
* @return 1 to sent a reply straight away, for like cache response so that
|
||||
* no allocation needs to be done. And only internal preallocated buffers
|
||||
* are used. Return 0 and save the repinfo to reply later, for responses
|
||||
* that need to be looked up. Return 0 and call comm_point_drop_reply on
|
||||
* the repinfo to drop the response.
|
||||
*/
|
||||
int
|
||||
worker_handle_request(struct comm_point* c, void* arg, int error,
|
||||
struct comm_reply* repinfo)
|
||||
@@ -1471,6 +1497,8 @@ worker_handle_request(struct comm_point* c, void* arg, int error,
|
||||
struct reply_info* partial_rep = NULL;
|
||||
struct query_info* lookup_qinfo = &qinfo;
|
||||
struct query_info qinfo_tmp; /* placeholder for lookup_qinfo */
|
||||
uint8_t* alias_orig_qname = NULL; /* original qname for logs, if
|
||||
a local_alias is used to change the qname. */
|
||||
struct respip_client_info* cinfo = NULL, cinfo_tmp;
|
||||
struct timeval wait_time;
|
||||
struct check_request_result check_result = {0,0};
|
||||
@@ -1488,7 +1516,7 @@ worker_handle_request(struct comm_point* c, void* arg, int error,
|
||||
if (worker->stats.max_query_time_us < wait_queue_time)
|
||||
worker->stats.max_query_time_us = wait_queue_time;
|
||||
if(wait_queue_time >
|
||||
(long long)(worker->env.cfg->sock_queue_timeout * 1000000)) {
|
||||
(long long)worker->env.cfg->sock_queue_timeout * 1000000) {
|
||||
/* count and drop queries that were sitting in the socket queue too long */
|
||||
worker->stats.num_queries_timed_out++;
|
||||
return 0;
|
||||
@@ -1510,6 +1538,10 @@ worker_handle_request(struct comm_point* c, void* arg, int error,
|
||||
"dnscrypt: worker check request: bad query.");
|
||||
log_addr(VERB_CLIENT,"from",&repinfo->client_addr,
|
||||
repinfo->client_addrlen);
|
||||
if(check_result.value != -1) {
|
||||
query_error(c->buffer, check_result.value, 0);
|
||||
return 1;
|
||||
}
|
||||
comm_point_drop_reply(repinfo);
|
||||
return 0;
|
||||
}
|
||||
@@ -1518,8 +1550,13 @@ worker_handle_request(struct comm_point* c, void* arg, int error,
|
||||
"dnscrypt: worker parse request: formerror.");
|
||||
log_addr(VERB_CLIENT, "from", &repinfo->client_addr,
|
||||
repinfo->client_addrlen);
|
||||
comm_point_drop_reply(repinfo);
|
||||
return 0;
|
||||
if(worker_err_ratelimit(worker, LDNS_RCODE_FORMERR) == -1) {
|
||||
comm_point_drop_reply(repinfo);
|
||||
return 0;
|
||||
}
|
||||
query_error(c->buffer, LDNS_RCODE_FORMERR, 0);
|
||||
sldns_buffer_copy(c->dnscrypt_buffer, c->buffer);
|
||||
return 1;
|
||||
}
|
||||
dname_str(qinfo.qname, buf);
|
||||
if(!(qinfo.qtype == LDNS_RR_TYPE_TXT &&
|
||||
@@ -1530,9 +1567,15 @@ worker_handle_request(struct comm_point* c, void* arg, int error,
|
||||
worker->daemon->dnscenv->provider_name,
|
||||
sldns_rr_descript(qinfo.qtype)->_name,
|
||||
buf);
|
||||
comm_point_drop_reply(repinfo);
|
||||
if(worker_err_ratelimit(worker, LDNS_RCODE_SERVFAIL) == -1) {
|
||||
comm_point_drop_reply(repinfo);
|
||||
return 0;
|
||||
}
|
||||
query_error(c->buffer, LDNS_RCODE_SERVFAIL,
|
||||
qinfo.qname_len);
|
||||
worker->stats.num_query_dnscrypt_cleartext++;
|
||||
return 0;
|
||||
sldns_buffer_copy(c->dnscrypt_buffer, c->buffer);
|
||||
return 1;
|
||||
}
|
||||
worker->stats.num_query_dnscrypt_cert++;
|
||||
sldns_buffer_rewind(c->buffer);
|
||||
@@ -1572,9 +1615,7 @@ worker_handle_request(struct comm_point* c, void* arg, int error,
|
||||
verbose(VERB_ALGO, "worker check request: bad query.");
|
||||
log_addr(VERB_CLIENT,"from",&repinfo->client_addr, repinfo->client_addrlen);
|
||||
if(check_result.value != -1) {
|
||||
LDNS_QR_SET(sldns_buffer_begin(c->buffer));
|
||||
LDNS_RCODE_SET(sldns_buffer_begin(c->buffer),
|
||||
check_result.value);
|
||||
query_error(c->buffer, check_result.value, 0);
|
||||
return 1;
|
||||
}
|
||||
comm_point_drop_reply(repinfo);
|
||||
@@ -1608,10 +1649,7 @@ worker_handle_request(struct comm_point* c, void* arg, int error,
|
||||
comm_point_drop_reply(repinfo);
|
||||
return 0;
|
||||
}
|
||||
sldns_buffer_rewind(c->buffer);
|
||||
LDNS_QR_SET(sldns_buffer_begin(c->buffer));
|
||||
LDNS_RCODE_SET(sldns_buffer_begin(c->buffer),
|
||||
LDNS_RCODE_FORMERR);
|
||||
query_error(c->buffer, LDNS_RCODE_FORMERR, 0);
|
||||
goto send_reply;
|
||||
}
|
||||
if(worker->env.cfg->log_queries) {
|
||||
@@ -1624,10 +1662,11 @@ worker_handle_request(struct comm_point* c, void* arg, int error,
|
||||
verbose(VERB_ALGO, "worker request: refused zone transfer.");
|
||||
log_addr(VERB_CLIENT, "from", &repinfo->client_addr,
|
||||
repinfo->client_addrlen);
|
||||
sldns_buffer_rewind(c->buffer);
|
||||
LDNS_QR_SET(sldns_buffer_begin(c->buffer));
|
||||
LDNS_RCODE_SET(sldns_buffer_begin(c->buffer),
|
||||
LDNS_RCODE_REFUSED);
|
||||
if(worker_err_ratelimit(worker, LDNS_RCODE_REFUSED) == -1) {
|
||||
comm_point_drop_reply(repinfo);
|
||||
return 0;
|
||||
}
|
||||
query_error(c->buffer, LDNS_RCODE_REFUSED, qinfo.qname_len);
|
||||
if(worker->stats.extended) {
|
||||
worker->stats.qtype[qinfo.qtype]++;
|
||||
}
|
||||
@@ -1646,10 +1685,7 @@ worker_handle_request(struct comm_point* c, void* arg, int error,
|
||||
comm_point_drop_reply(repinfo);
|
||||
return 0;
|
||||
}
|
||||
sldns_buffer_rewind(c->buffer);
|
||||
LDNS_QR_SET(sldns_buffer_begin(c->buffer));
|
||||
LDNS_RCODE_SET(sldns_buffer_begin(c->buffer),
|
||||
LDNS_RCODE_FORMERR);
|
||||
query_error(c->buffer, LDNS_RCODE_FORMERR, qinfo.qname_len);
|
||||
if(worker->stats.extended) {
|
||||
worker->stats.qtype[qinfo.qtype]++;
|
||||
}
|
||||
@@ -1657,13 +1693,17 @@ worker_handle_request(struct comm_point* c, void* arg, int error,
|
||||
}
|
||||
if((ret=parse_edns_from_query_pkt(
|
||||
c->buffer, &edns, worker->env.cfg, c, repinfo,
|
||||
(worker->env.now ? *worker->env.now : time(NULL)),
|
||||
worker->scratchpad,
|
||||
*worker->env.now, worker->scratchpad,
|
||||
worker->daemon->cookie_secrets)) != 0) {
|
||||
struct edns_data reply_edns;
|
||||
verbose(VERB_ALGO, "worker parse edns: formerror.");
|
||||
log_addr(VERB_CLIENT, "from", &repinfo->client_addr,
|
||||
repinfo->client_addrlen);
|
||||
if(worker_err_ratelimit(worker, ret) == -1) {
|
||||
comm_point_drop_reply(repinfo);
|
||||
regional_free_all(worker->scratchpad);
|
||||
return 0;
|
||||
}
|
||||
memset(&reply_edns, 0, sizeof(reply_edns));
|
||||
reply_edns.edns_present = 1;
|
||||
error_encode(c->buffer, ret, &qinfo,
|
||||
@@ -1680,6 +1720,11 @@ worker_handle_request(struct comm_point* c, void* arg, int error,
|
||||
verbose(VERB_ALGO, "query with bad edns version.");
|
||||
log_addr(VERB_CLIENT, "from", &repinfo->client_addr,
|
||||
repinfo->client_addrlen);
|
||||
if(worker_err_ratelimit(worker, EDNS_RCODE_BADVERS) == -1) {
|
||||
comm_point_drop_reply(repinfo);
|
||||
regional_free_all(worker->scratchpad);
|
||||
return 0;
|
||||
}
|
||||
extended_error_encode(c->buffer, EDNS_RCODE_BADVERS, &qinfo,
|
||||
*(uint16_t*)(void *)sldns_buffer_begin(c->buffer),
|
||||
sldns_buffer_read_u16_at(c->buffer, 2), 0, &edns);
|
||||
@@ -1707,6 +1752,7 @@ worker_handle_request(struct comm_point* c, void* arg, int error,
|
||||
repinfo->client_addrlen, edns.cookie_valid,
|
||||
c->buffer)) {
|
||||
worker->stats.num_queries_ip_ratelimited++;
|
||||
regional_free_all(worker->scratchpad);
|
||||
comm_point_drop_reply(repinfo);
|
||||
return 0;
|
||||
}
|
||||
@@ -1724,6 +1770,11 @@ worker_handle_request(struct comm_point* c, void* arg, int error,
|
||||
|
||||
else if(edns.cookie_present) {
|
||||
/* Cookie present, but not valid: Cookie was bad! */
|
||||
if(worker_err_ratelimit(worker, LDNS_EXT_RCODE_BADCOOKIE) == -1) {
|
||||
comm_point_drop_reply(repinfo);
|
||||
regional_free_all(worker->scratchpad);
|
||||
return 0;
|
||||
}
|
||||
extended_error_encode(c->buffer,
|
||||
LDNS_EXT_RCODE_BADCOOKIE, &qinfo,
|
||||
*(uint16_t*)(void *)
|
||||
@@ -1738,6 +1789,11 @@ worker_handle_request(struct comm_point* c, void* arg, int error,
|
||||
"need cookie or stateful transport");
|
||||
log_addr(VERB_ALGO, "from",&repinfo->remote_addr
|
||||
, repinfo->remote_addrlen);
|
||||
if(worker_err_ratelimit(worker, LDNS_RCODE_REFUSED) == -1) {
|
||||
comm_point_drop_reply(repinfo);
|
||||
regional_free_all(worker->scratchpad);
|
||||
return 0;
|
||||
}
|
||||
EDNS_OPT_LIST_APPEND_EDE(&edns.opt_list_out,
|
||||
worker->scratchpad, LDNS_EDE_OTHER,
|
||||
"DNS Cookie needed for UDP replies");
|
||||
@@ -1764,14 +1820,14 @@ worker_handle_request(struct comm_point* c, void* arg, int error,
|
||||
verbose(VERB_ALGO, "worker request: edns is too small.");
|
||||
log_addr(VERB_CLIENT, "from", &repinfo->client_addr,
|
||||
repinfo->client_addrlen);
|
||||
LDNS_QR_SET(sldns_buffer_begin(c->buffer));
|
||||
if(worker_err_ratelimit(worker, LDNS_RCODE_SERVFAIL) == -1) {
|
||||
comm_point_drop_reply(repinfo);
|
||||
regional_free_all(worker->scratchpad);
|
||||
return 0;
|
||||
}
|
||||
/* A small error without qname, and TC flag on. */
|
||||
query_error(c->buffer, LDNS_RCODE_SERVFAIL, 0);
|
||||
LDNS_TC_SET(sldns_buffer_begin(c->buffer));
|
||||
LDNS_RCODE_SET(sldns_buffer_begin(c->buffer),
|
||||
LDNS_RCODE_SERVFAIL);
|
||||
sldns_buffer_set_position(c->buffer, LDNS_HEADER_SIZE);
|
||||
sldns_buffer_write_at(c->buffer, 4,
|
||||
(uint8_t*)"\0\0\0\0\0\0\0\0", 8);
|
||||
sldns_buffer_flip(c->buffer);
|
||||
regional_free_all(worker->scratchpad);
|
||||
goto send_reply;
|
||||
}
|
||||
@@ -1779,7 +1835,13 @@ worker_handle_request(struct comm_point* c, void* arg, int error,
|
||||
server_stats_insquery(&worker->stats, c, qinfo.qtype,
|
||||
qinfo.qclass, &edns, repinfo);
|
||||
if(c->type != comm_udp)
|
||||
#ifdef USE_DNSCRYPT
|
||||
edns.udp_size = (c->dnscrypt && repinfo->is_dnscrypted)
|
||||
? sldns_buffer_capacity(c->buffer) - DNSCRYPT_REPLY_HEADER_SIZE
|
||||
: 65535;
|
||||
#else
|
||||
edns.udp_size = 65535; /* max size for TCP replies */
|
||||
#endif
|
||||
if(qinfo.qclass == LDNS_RR_CLASS_CH && answer_chaos(worker, &qinfo,
|
||||
&edns, repinfo, c->buffer)) {
|
||||
regional_free_all(worker->scratchpad);
|
||||
@@ -1818,8 +1880,9 @@ worker_handle_request(struct comm_point* c, void* arg, int error,
|
||||
goto send_reply;
|
||||
}
|
||||
if(worker->env.auth_zones &&
|
||||
auth_zones_answer(worker->env.auth_zones, &worker->env,
|
||||
&qinfo, &edns, repinfo, c->buffer, worker->scratchpad)) {
|
||||
auth_zones_downstream_answer(worker->env.auth_zones,
|
||||
&worker->env, &qinfo, &edns, repinfo, c->buffer,
|
||||
worker->scratchpad)) {
|
||||
regional_free_all(worker->scratchpad);
|
||||
if(sldns_buffer_limit(c->buffer) == 0) {
|
||||
comm_point_drop_reply(repinfo);
|
||||
@@ -1855,6 +1918,15 @@ worker_handle_request(struct comm_point* c, void* arg, int error,
|
||||
* ACLs allow the snooping. */
|
||||
if(!(LDNS_RD_WIRE(sldns_buffer_begin(c->buffer))) &&
|
||||
acl != acl_allow_snoop ) {
|
||||
log_addr(VERB_ALGO, "refused nonrec (cache snoop) query from",
|
||||
&repinfo->client_addr, repinfo->client_addrlen);
|
||||
/* This ratelimited error query is accounted in the stats,
|
||||
* as an incoming query. */
|
||||
if(worker_err_ratelimit(worker, LDNS_RCODE_REFUSED) == -1) {
|
||||
comm_point_drop_reply(repinfo);
|
||||
regional_free_all(worker->scratchpad);
|
||||
return 0;
|
||||
}
|
||||
if(worker->env.cfg->ede) {
|
||||
EDNS_OPT_LIST_APPEND_EDE(&edns.opt_list_out,
|
||||
worker->scratchpad, LDNS_EDE_NOT_AUTHORITATIVE, "");
|
||||
@@ -1863,29 +1935,22 @@ worker_handle_request(struct comm_point* c, void* arg, int error,
|
||||
*(uint16_t*)(void *)sldns_buffer_begin(c->buffer),
|
||||
sldns_buffer_read_u16_at(c->buffer, 2), &edns);
|
||||
regional_free_all(worker->scratchpad);
|
||||
log_addr(VERB_ALGO, "refused nonrec (cache snoop) query from",
|
||||
&repinfo->client_addr, repinfo->client_addrlen);
|
||||
|
||||
goto send_reply;
|
||||
}
|
||||
|
||||
/* If we've found a local alias, replace the qname with the alias
|
||||
* target before resolving it. */
|
||||
if(qinfo.local_alias) {
|
||||
struct ub_packed_rrset_key* rrset = qinfo.local_alias->rrset;
|
||||
struct packed_rrset_data* d = rrset->entry.data;
|
||||
|
||||
/* Sanity check: our current implementation only supports
|
||||
* a single CNAME RRset as a local alias. */
|
||||
if(qinfo.local_alias->next ||
|
||||
rrset->rk.type != htons(LDNS_RR_TYPE_CNAME) ||
|
||||
d->count != 1) {
|
||||
log_err("assumption failure: unexpected local alias");
|
||||
if(qinfo.local_alias->rrset &&
|
||||
qinfo.local_alias->rrset->rk.dname)
|
||||
/* Store the original qname, used for logs, since
|
||||
* local_alias can be removed by region_free_all. */
|
||||
alias_orig_qname = qinfo.local_alias->rrset->rk.dname;
|
||||
if(!local_alias_shallow_copy_qname(qinfo.local_alias, &qinfo.qname,
|
||||
&qinfo.qname_len)) {
|
||||
regional_free_all(worker->scratchpad);
|
||||
return 0; /* drop it */
|
||||
}
|
||||
qinfo.qname = d->rr_data[0] + 2;
|
||||
qinfo.qname_len = d->rr_len[0] - 2;
|
||||
}
|
||||
|
||||
/* If we may apply IP-based actions to the answer, build the client
|
||||
@@ -1928,7 +1993,7 @@ lookup_cache:
|
||||
&alias_rrset, &partial_rep, rep,
|
||||
*(uint16_t*)(void *)sldns_buffer_begin(c->buffer),
|
||||
sldns_buffer_read_u16_at(c->buffer, 2), repinfo,
|
||||
&edns)) {
|
||||
&edns, &rpz_passthru)) {
|
||||
/* prefetch it if the prefetch TTL expired.
|
||||
* Note that if there is more than one pass
|
||||
* its qname must be that used for cache
|
||||
@@ -1936,11 +2001,11 @@ lookup_cache:
|
||||
if((worker->env.cfg->prefetch &&
|
||||
rep->prefetch_ttl <= *worker->env.now) ||
|
||||
(worker->env.cfg->serve_expired &&
|
||||
rep->ttl < *worker->env.now &&
|
||||
TTL_IS_EXPIRED(rep->ttl, *worker->env.now) &&
|
||||
!(*worker->env.now < rep->serve_expired_norec_ttl))) {
|
||||
time_t leeway = rep->ttl - *worker->env.now;
|
||||
if(rep->ttl < *worker->env.now)
|
||||
leeway = 0;
|
||||
time_t leeway =
|
||||
TTL_IS_EXPIRED(rep->ttl, *worker->env.now)
|
||||
? 0 : rep->ttl - *worker->env.now;
|
||||
lock_rw_unlock(&e->lock);
|
||||
|
||||
reply_and_prefetch(worker, lookup_qinfo,
|
||||
@@ -2046,11 +2111,10 @@ send_reply_rc:
|
||||
{
|
||||
struct timeval tv;
|
||||
memset(&tv, 0, sizeof(tv));
|
||||
if(qinfo.local_alias && qinfo.local_alias->rrset &&
|
||||
qinfo.local_alias->rrset->rk.dname) {
|
||||
if(alias_orig_qname) {
|
||||
/* log original qname, before the local alias was
|
||||
* used to resolve that CNAME to something else */
|
||||
qinfo.qname = qinfo.local_alias->rrset->rk.dname;
|
||||
qinfo.qname = alias_orig_qname;
|
||||
log_reply_info(NO_VERBOSE, &qinfo,
|
||||
&repinfo->client_addr, repinfo->client_addrlen,
|
||||
tv, 1, c->buffer,
|
||||
@@ -2065,7 +2129,7 @@ send_reply_rc:
|
||||
}
|
||||
}
|
||||
#ifdef USE_DNSCRYPT
|
||||
if(!dnsc_handle_uncurved_request(repinfo)) {
|
||||
if(!dnsc_handle_uncurved_request(repinfo, c->buffer)) {
|
||||
return 0;
|
||||
}
|
||||
#endif
|
||||
@@ -2113,10 +2177,37 @@ worker_restart_timer(struct worker* worker)
|
||||
{
|
||||
if(worker->env.cfg->stat_interval > 0) {
|
||||
struct timeval tv;
|
||||
if(worker->daemon->stat_time_specific) {
|
||||
struct timeval dest, now;
|
||||
int interval = worker->env.cfg->stat_interval;
|
||||
int offset = worker->daemon->stat_time_offset;
|
||||
int nows, spec;
|
||||
if(gettimeofday(&now, NULL) < 0)
|
||||
log_err("gettimeofday: %s", strerror(errno));
|
||||
#ifndef S_SPLINT_S
|
||||
tv.tv_sec = worker->env.cfg->stat_interval;
|
||||
tv.tv_usec = 0;
|
||||
nows = (int)now.tv_sec;
|
||||
/* The next time is on the timer interval, at the
|
||||
* specific offset, time value % interval = offset. */
|
||||
/* It relies on the integer division below to drop the
|
||||
* remainder in order to calculate the expected
|
||||
* result. */
|
||||
spec = ((nows-offset)/interval+1)*interval+offset;
|
||||
/* This is instead of an assertion, and should not
|
||||
* be needed. So assert(spec > nows), tv is going to
|
||||
* be positive. */
|
||||
if(spec<=nows) spec += interval;
|
||||
dest.tv_sec = spec;
|
||||
dest.tv_usec = 0;
|
||||
#endif
|
||||
/* Subtract in timeval, so the fractions of a second
|
||||
* are rounded to the whole specific time. */
|
||||
timeval_subtract(&tv, &dest, &now);
|
||||
} else {
|
||||
#ifndef S_SPLINT_S
|
||||
tv.tv_sec = worker->env.cfg->stat_interval;
|
||||
tv.tv_usec = 0;
|
||||
#endif
|
||||
}
|
||||
comm_timer_set(worker->stat_timer, &tv);
|
||||
}
|
||||
}
|
||||
@@ -2151,23 +2242,16 @@ void worker_probe_timer_cb(void* arg)
|
||||
}
|
||||
|
||||
struct worker*
|
||||
worker_create(struct daemon* daemon, int id, int* ports, int n)
|
||||
worker_create(struct daemon* daemon, int id)
|
||||
{
|
||||
unsigned int seed;
|
||||
struct worker* worker = (struct worker*)calloc(1,
|
||||
sizeof(struct worker));
|
||||
if(!worker)
|
||||
return NULL;
|
||||
worker->numports = n;
|
||||
worker->ports = (int*)memdup(ports, sizeof(int)*n);
|
||||
if(!worker->ports) {
|
||||
free(worker);
|
||||
return NULL;
|
||||
}
|
||||
worker->daemon = daemon;
|
||||
worker->thread_num = id;
|
||||
if(!(worker->cmd = tube_create())) {
|
||||
free(worker->ports);
|
||||
free(worker);
|
||||
return NULL;
|
||||
}
|
||||
@@ -2175,7 +2259,6 @@ worker_create(struct daemon* daemon, int id, int* ports, int n)
|
||||
if(!(worker->rndstate = ub_initstate(daemon->rand))) {
|
||||
log_err("could not init random numbers.");
|
||||
tube_delete(worker->cmd);
|
||||
free(worker->ports);
|
||||
free(worker);
|
||||
return NULL;
|
||||
}
|
||||
@@ -2191,9 +2274,6 @@ worker_init(struct worker* worker, struct config_file *cfg,
|
||||
struct dt_env* dtenv = &worker->dtenv;
|
||||
#else
|
||||
void* dtenv = NULL;
|
||||
#endif
|
||||
#ifdef HAVE_GETTID
|
||||
worker->thread_tid = gettid();
|
||||
#endif
|
||||
worker->need_to_exit = 0;
|
||||
worker->base = comm_base_create(do_sigs);
|
||||
@@ -2277,14 +2357,14 @@ worker_init(struct worker* worker, struct config_file *cfg,
|
||||
cfg->out_ifs, cfg->num_out_ifs, cfg->do_ip4, cfg->do_ip6,
|
||||
cfg->do_tcp?cfg->outgoing_num_tcp:0, cfg->ip_dscp,
|
||||
worker->daemon->env->infra_cache, worker->rndstate,
|
||||
cfg->use_caps_bits_for_id, worker->ports, worker->numports,
|
||||
cfg->use_caps_bits_for_id,
|
||||
cfg->unwanted_threshold, cfg->outgoing_tcp_mss,
|
||||
&worker_alloc_cleanup, worker,
|
||||
cfg->do_udp || cfg->udp_upstream_without_downstream,
|
||||
worker->daemon->connect_dot_sslctx, cfg->delay_close,
|
||||
cfg->tls_use_sni, dtenv, cfg->udp_connect,
|
||||
cfg->max_reuse_tcp_queries, cfg->tcp_reuse_timeout,
|
||||
cfg->tcp_auth_query_timeout);
|
||||
cfg->tcp_auth_query_timeout, worker->daemon->shared_ports);
|
||||
if(!worker->back) {
|
||||
log_err("could not create outgoing sockets");
|
||||
worker_delete(worker);
|
||||
@@ -2303,6 +2383,8 @@ worker_init(struct worker* worker, struct config_file *cfg,
|
||||
worker_stat_timer_cb, worker);
|
||||
if(!worker->stat_timer) {
|
||||
log_err("could not create statistics timer");
|
||||
worker_delete(worker);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* we use the msg_buffer_size as a good estimate for what the
|
||||
@@ -2435,7 +2517,6 @@ worker_delete(struct worker* worker)
|
||||
tube_delete(worker->cmd);
|
||||
comm_timer_delete(worker->stat_timer);
|
||||
comm_timer_delete(worker->env.probe_timer);
|
||||
free(worker->ports);
|
||||
if(worker->thread_num == 0) {
|
||||
#ifdef UB_ON_WINDOWS
|
||||
wsvc_desetup_worker(worker);
|
||||
@@ -2456,6 +2537,8 @@ worker_delete(struct worker* worker)
|
||||
/* don't touch worker->alloc, as it's maintained in daemon */
|
||||
regional_destroy(worker->env.scratch);
|
||||
regional_destroy(worker->scratchpad);
|
||||
/* The thread id can reference this worker's id value, so clear it. */
|
||||
log_thread_set(NULL);
|
||||
free(worker);
|
||||
}
|
||||
|
||||
@@ -2464,7 +2547,8 @@ worker_send_query(struct query_info* qinfo, uint16_t flags, int dnssec,
|
||||
int want_dnssec, int nocaps, int check_ratelimit,
|
||||
struct sockaddr_storage* addr, socklen_t addrlen, uint8_t* zone,
|
||||
size_t zonelen, int tcp_upstream, int ssl_upstream, char* tls_auth_name,
|
||||
struct module_qstate* q, int* was_ratelimited)
|
||||
struct module_qstate* q, int* was_ratelimited,
|
||||
int* ratelimit_incremented)
|
||||
{
|
||||
struct worker* worker = q->env->worker;
|
||||
struct outbound_entry* e = (struct outbound_entry*)regional_alloc(
|
||||
@@ -2476,7 +2560,7 @@ worker_send_query(struct query_info* qinfo, uint16_t flags, int dnssec,
|
||||
want_dnssec, nocaps, check_ratelimit, tcp_upstream,
|
||||
ssl_upstream, tls_auth_name, addr, addrlen, zone, zonelen, q,
|
||||
worker_handle_service_reply, e, worker->back->udp_buff, q->env,
|
||||
was_ratelimited);
|
||||
was_ratelimited, ratelimit_incremented);
|
||||
if(!e->qsent) {
|
||||
return NULL;
|
||||
}
|
||||
@@ -2525,7 +2609,8 @@ struct outbound_entry* libworker_send_query(
|
||||
struct sockaddr_storage* ATTR_UNUSED(addr), socklen_t ATTR_UNUSED(addrlen),
|
||||
uint8_t* ATTR_UNUSED(zone), size_t ATTR_UNUSED(zonelen), int ATTR_UNUSED(tcp_upstream),
|
||||
int ATTR_UNUSED(ssl_upstream), char* ATTR_UNUSED(tls_auth_name),
|
||||
struct module_qstate* ATTR_UNUSED(q), int* ATTR_UNUSED(was_ratelimited))
|
||||
struct module_qstate* ATTR_UNUSED(q), int* ATTR_UNUSED(was_ratelimited),
|
||||
int* ATTR_UNUSED(ratelimit_incremented))
|
||||
{
|
||||
log_assert(0);
|
||||
return 0;
|
||||
@@ -2567,6 +2652,11 @@ void libworker_event_done_cb(void* ATTR_UNUSED(arg), int ATTR_UNUSED(rcode),
|
||||
log_assert(0);
|
||||
}
|
||||
|
||||
void libworker_alloc_cleanup(void* ATTR_UNUSED(arg))
|
||||
{
|
||||
log_assert(0);
|
||||
}
|
||||
|
||||
int context_query_cmp(const void* ATTR_UNUSED(a), const void* ATTR_UNUSED(b))
|
||||
{
|
||||
log_assert(0);
|
||||
|
||||
+1
-7
@@ -104,10 +104,6 @@ struct worker {
|
||||
struct listen_dnsport* front;
|
||||
/** the backside outside network interface to the auth servers */
|
||||
struct outside_network* back;
|
||||
/** ports to be used by this worker. */
|
||||
int* ports;
|
||||
/** number of ports for this worker */
|
||||
int numports;
|
||||
/** the signal handler */
|
||||
struct comm_signal* comsig;
|
||||
/** commpoint to listen to commands. */
|
||||
@@ -146,11 +142,9 @@ struct worker {
|
||||
* with backpointers only. Use worker_init on it later.
|
||||
* @param daemon: the daemon that this worker thread is part of.
|
||||
* @param id: the thread number from 0.. numthreads-1.
|
||||
* @param ports: the ports it is allowed to use, array.
|
||||
* @param n: the number of ports.
|
||||
* @return: the new worker or NULL on alloc failure.
|
||||
*/
|
||||
struct worker* worker_create(struct daemon* daemon, int id, int* ports, int n);
|
||||
struct worker* worker_create(struct daemon* daemon, int id);
|
||||
|
||||
/**
|
||||
* Initialize worker.
|
||||
|
||||
+72
-20
@@ -366,22 +366,23 @@ static int
|
||||
dns64_apply_cfg(struct dns64_env* dns64_env, struct config_file* cfg)
|
||||
{
|
||||
struct config_strlist* s;
|
||||
verbose(VERB_ALGO, "dns64-prefix: %s", cfg->dns64_prefix);
|
||||
if (!netblockstrtoaddr(cfg->dns64_prefix ? cfg->dns64_prefix :
|
||||
DEFAULT_DNS64_PREFIX, 0, &dns64_env->prefix_addr,
|
||||
const char* dns64_prefix = cfg->dns64_prefix ?
|
||||
cfg->dns64_prefix : DEFAULT_DNS64_PREFIX;
|
||||
verbose(VERB_ALGO, "dns64-prefix: %s", dns64_prefix);
|
||||
if (!netblockstrtoaddr(dns64_prefix, 0, &dns64_env->prefix_addr,
|
||||
&dns64_env->prefix_addrlen, &dns64_env->prefix_net)) {
|
||||
log_err("cannot parse dns64-prefix netblock: %s", cfg->dns64_prefix);
|
||||
log_err("cannot parse dns64-prefix netblock: %s", dns64_prefix);
|
||||
return 0;
|
||||
}
|
||||
if (!addr_is_ip6(&dns64_env->prefix_addr, dns64_env->prefix_addrlen)) {
|
||||
log_err("dns64_prefix is not IPv6: %s", cfg->dns64_prefix);
|
||||
log_err("dns64_prefix is not IPv6: %s", dns64_prefix);
|
||||
return 0;
|
||||
}
|
||||
if (dns64_env->prefix_net != 32 && dns64_env->prefix_net != 40 &&
|
||||
dns64_env->prefix_net != 48 && dns64_env->prefix_net != 56 &&
|
||||
dns64_env->prefix_net != 64 && dns64_env->prefix_net != 96 ) {
|
||||
log_err("dns64-prefix length it not 32, 40, 48, 56, 64 or 96: %s",
|
||||
cfg->dns64_prefix);
|
||||
log_err("dns64-prefix length is not 32, 40, 48, 56, 64 or 96: %s",
|
||||
dns64_prefix);
|
||||
return 0;
|
||||
}
|
||||
for(s = cfg->dns64_ignore_aaaa; s; s = s->next) {
|
||||
@@ -496,8 +497,8 @@ handle_ipv6_ptr(struct module_qstate* qstate, int id)
|
||||
|
||||
/* Create the new sub-query. */
|
||||
fptr_ok(fptr_whitelist_modenv_attach_sub(qstate->env->attach_sub));
|
||||
if(!(*qstate->env->attach_sub)(qstate, &qinfo, qstate->query_flags, 0, 0,
|
||||
&subq))
|
||||
if(!(*qstate->env->attach_sub)(qstate, &qinfo, qstate->client_info,
|
||||
qstate->query_flags, 0, 0, &subq))
|
||||
return module_error;
|
||||
if (subq) {
|
||||
subq->curmod = id;
|
||||
@@ -522,8 +523,8 @@ generate_type_A_query(struct module_qstate* qstate, int id)
|
||||
|
||||
/* Start the sub-query. */
|
||||
fptr_ok(fptr_whitelist_modenv_attach_sub(qstate->env->attach_sub));
|
||||
if(!(*qstate->env->attach_sub)(qstate, &qinfo, qstate->query_flags, 0,
|
||||
0, &subq))
|
||||
if(!(*qstate->env->attach_sub)(qstate, &qinfo, qstate->client_info,
|
||||
qstate->query_flags, 0, 0, &subq))
|
||||
{
|
||||
verbose(VERB_ALGO, "dns64: sub-query creation failed");
|
||||
return module_error;
|
||||
@@ -631,7 +632,7 @@ handle_event_moddone(struct module_qstate* qstate, int id)
|
||||
|
||||
/* 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
|
||||
* ones generated by us to retrieve the A/PTR record to use for
|
||||
* synth. */
|
||||
int could_synth =
|
||||
qstate->qinfo.qtype == LDNS_RR_TYPE_AAAA &&
|
||||
@@ -642,6 +643,12 @@ handle_event_moddone(struct module_qstate* qstate, int id)
|
||||
qstate->return_msg->rep &&
|
||||
reply_find_answer_rrset(&qstate->qinfo, qstate->return_msg->rep);
|
||||
int synth_qname = 0;
|
||||
if(could_synth && !has_data && qstate->env->need_to_validate &&
|
||||
qstate->return_msg && qstate->return_msg->rep &&
|
||||
qstate->return_msg->rep->security == sec_status_bogus) {
|
||||
verbose(VERB_ALGO, "dns64: bogus AAAA reply not synthesized");
|
||||
could_synth = 0;
|
||||
}
|
||||
|
||||
if(could_synth &&
|
||||
(!has_data ||
|
||||
@@ -653,8 +660,11 @@ handle_event_moddone(struct module_qstate* qstate, int id)
|
||||
|
||||
/* Store the response in cache. */
|
||||
if( (!iq || !iq->started_no_cache_store) &&
|
||||
!qstate->rpz_applied && !qstate->rpz_passthru &&
|
||||
!qstate->is_subnet_answer &&
|
||||
qstate->return_msg &&
|
||||
qstate->return_msg->rep &&
|
||||
!qstate->fwd_stub_no_cache &&
|
||||
!dns_cache_store(
|
||||
qstate->env, &qstate->qinfo, qstate->return_msg->rep,
|
||||
0, qstate->prefetch_leeway, 0, NULL,
|
||||
@@ -716,8 +726,15 @@ dns64_operate(struct module_qstate* qstate, enum module_ev event, int id,
|
||||
}
|
||||
if(qstate->ext_state[id] == module_finished) {
|
||||
iq = (struct dns64_qstate*)qstate->minfo[id];
|
||||
if(iq && iq->state != DNS64_INTERNAL_QUERY)
|
||||
qstate->no_cache_store = iq->started_no_cache_store;
|
||||
if(iq && iq->state != DNS64_INTERNAL_QUERY) {
|
||||
if(qstate->fwd_stub_no_cache) {
|
||||
/* If the forward/stub has no cache, then
|
||||
* continue with the query with no cache. */
|
||||
qstate->no_cache_store = qstate->fwd_stub_no_cache;
|
||||
} else {
|
||||
qstate->no_cache_store = iq->started_no_cache_store;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -824,6 +841,7 @@ dns64_adjust_a(int id, struct module_qstate* super, struct module_qstate* qstate
|
||||
size_t i, s;
|
||||
struct packed_rrset_data* fd, *dd;
|
||||
struct ub_packed_rrset_key* fk, *dk;
|
||||
int allocated_return_msg = 0;
|
||||
|
||||
verbose(VERB_ALGO, "converting A answers to AAAA answers");
|
||||
|
||||
@@ -839,6 +857,7 @@ dns64_adjust_a(int id, struct module_qstate* super, struct module_qstate* qstate
|
||||
return;
|
||||
memset(super->return_msg, 0, sizeof(*super->return_msg));
|
||||
super->return_msg->qinfo = super->qinfo;
|
||||
allocated_return_msg = 1;
|
||||
}
|
||||
|
||||
rep = qstate->return_msg->rep;
|
||||
@@ -851,11 +870,14 @@ dns64_adjust_a(int id, struct module_qstate* super, struct module_qstate* qstate
|
||||
rep->serve_expired_norec_ttl,
|
||||
rep->an_numrrsets, rep->ns_numrrsets, rep->ar_numrrsets,
|
||||
rep->rrset_count, rep->security, LDNS_EDE_NONE);
|
||||
if(!cp)
|
||||
if(!cp) {
|
||||
if(allocated_return_msg) super->return_msg = NULL;
|
||||
return;
|
||||
}
|
||||
|
||||
/* allocate ub_key structures special or not */
|
||||
if(!reply_info_alloc_rrset_keys(cp, NULL, super->region)) {
|
||||
if(allocated_return_msg) super->return_msg = NULL;
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -870,8 +892,10 @@ dns64_adjust_a(int id, struct module_qstate* super, struct module_qstate* qstate
|
||||
if(i<rep->an_numrrsets && fk->rk.type == htons(LDNS_RR_TYPE_A)) {
|
||||
/* also sets dk->entry.hash */
|
||||
dns64_synth_aaaa_data(fk, fd, dk, &dd, super->region, dns64_env);
|
||||
if(!dd)
|
||||
if(!dd) {
|
||||
if(allocated_return_msg) super->return_msg = NULL;
|
||||
return;
|
||||
}
|
||||
/* Delete negative AAAA record from cache stored by
|
||||
* the iterator module */
|
||||
rrset_cache_remove(super->env->rrset_cache, dk->rk.dname,
|
||||
@@ -888,15 +912,19 @@ dns64_adjust_a(int id, struct module_qstate* super, struct module_qstate* qstate
|
||||
dk->rk.dname = (uint8_t*)regional_alloc_init(super->region,
|
||||
fk->rk.dname, fk->rk.dname_len);
|
||||
|
||||
if(!dk->rk.dname)
|
||||
if(!dk->rk.dname) {
|
||||
if(allocated_return_msg) super->return_msg = NULL;
|
||||
return;
|
||||
}
|
||||
|
||||
s = packed_rrset_sizeof(fd);
|
||||
dd = (struct packed_rrset_data*)regional_alloc_init(
|
||||
super->region, fd, s);
|
||||
|
||||
if(!dd)
|
||||
if(!dd) {
|
||||
if(allocated_return_msg) super->return_msg = NULL;
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
packed_rrset_ptr_fixup(dd);
|
||||
@@ -927,8 +955,10 @@ dns64_adjust_ptr(struct module_qstate* qstate, struct module_qstate* super)
|
||||
return;
|
||||
super->return_msg->qinfo = super->qinfo;
|
||||
if (!(super->return_msg->rep = reply_info_copy(qstate->return_msg->rep,
|
||||
NULL, super->region)))
|
||||
NULL, super->region))) {
|
||||
super->return_msg = NULL;
|
||||
return;
|
||||
}
|
||||
|
||||
/*
|
||||
* Adjust the domain name of the answer RR set so that it matches the
|
||||
@@ -997,6 +1027,21 @@ dns64_inform_super(struct module_qstate* qstate, int id,
|
||||
/* Use return code from A query in response to client. */
|
||||
if (super->return_rcode != LDNS_RCODE_NOERROR)
|
||||
super->return_rcode = qstate->return_rcode;
|
||||
/* RPZ applied to the subquery need to then change (not cache)
|
||||
* the super query. With the super query not cached, it is
|
||||
* going to run the state machine modules on incoming queries,
|
||||
* that fetch the subquery (cache) response, and modify it
|
||||
* according to the rpz policy. That makes the synthesized
|
||||
* super query also adjusted by rpz policies. But loses cache
|
||||
* hits. Even though the subquery likely is answered from cache,
|
||||
* internally in its state machine process. */
|
||||
if(qstate->rpz_applied)
|
||||
super->rpz_applied = 1;
|
||||
if(qstate->rpz_passthru)
|
||||
super->rpz_passthru = 1;
|
||||
|
||||
/* Since the super qstate has a new response, its errinf is removed. */
|
||||
super->errinf = NULL;
|
||||
|
||||
/* Generate a response suitable for the original query. */
|
||||
if (qstate->qinfo.qtype == LDNS_RR_TYPE_A) {
|
||||
@@ -1005,9 +1050,16 @@ dns64_inform_super(struct module_qstate* qstate, int id,
|
||||
log_assert(qstate->qinfo.qtype == LDNS_RR_TYPE_PTR);
|
||||
dns64_adjust_ptr(qstate, super);
|
||||
}
|
||||
/* If the sub-query has no cache store, then also the super query. */
|
||||
if(qstate->fwd_stub_no_cache)
|
||||
super->fwd_stub_no_cache = 1;
|
||||
|
||||
/* Store the generated response in cache. */
|
||||
if ( (!super_dq || !super_dq->started_no_cache_store) &&
|
||||
if ( super->return_msg && super->return_msg->rep &&
|
||||
(!super_dq || !super_dq->started_no_cache_store) &&
|
||||
!qstate->fwd_stub_no_cache &&
|
||||
!super->rpz_applied && !super->rpz_passthru &&
|
||||
!super->is_subnet_answer &&
|
||||
!dns_cache_store(super->env, &super->qinfo, super->return_msg->rep,
|
||||
0, super->prefetch_leeway, 0, NULL, super->query_flags,
|
||||
qstate->qstarttime, qstate->is_valrec))
|
||||
|
||||
+32
-5
@@ -361,7 +361,7 @@ dnscrypt_server_uncurve(struct dnsc_env* env,
|
||||
|
||||
len -= DNSCRYPT_QUERY_HEADER_SIZE;
|
||||
|
||||
while (*sldns_buffer_at(buffer, --len) == 0)
|
||||
while (len>0 && *sldns_buffer_at(buffer, --len) == 0)
|
||||
;
|
||||
|
||||
if (*sldns_buffer_at(buffer, len) != 0x80) {
|
||||
@@ -474,10 +474,18 @@ dnscrypt_server_curve(const dnsccert *cert,
|
||||
uint8_t *const buf = sldns_buffer_begin(buffer);
|
||||
size_t len = sldns_buffer_limit(buffer);
|
||||
|
||||
if(len + DNSCRYPT_REPLY_HEADER_SIZE > sldns_buffer_capacity(buffer))
|
||||
return -1;
|
||||
sldns_buffer_clear(buffer);
|
||||
|
||||
if(udp){
|
||||
if (max_len > max_reply_size)
|
||||
max_len = max_reply_size;
|
||||
}
|
||||
if(max_len > sldns_buffer_capacity(buffer))
|
||||
max_len = sldns_buffer_capacity(buffer);
|
||||
if(max_len > 65535)
|
||||
max_len = 65535;
|
||||
|
||||
|
||||
memcpy(nonce, client_nonce, crypto_box_HALF_NONCEBYTES);
|
||||
@@ -520,6 +528,7 @@ dnscrypt_server_curve(const dnsccert *cert,
|
||||
DNSCRYPT_MAGIC_HEADER_LEN,
|
||||
nonce,
|
||||
crypto_box_NONCEBYTES);
|
||||
sldns_buffer_flip(buffer);
|
||||
sldns_buffer_set_limit(buffer, len + DNSCRYPT_REPLY_HEADER_SIZE);
|
||||
return 0;
|
||||
}
|
||||
@@ -663,6 +672,8 @@ dnsc_find_cert(struct dnsc_env* dnscenv, struct sldns_buffer* buffer)
|
||||
}
|
||||
dnscrypt_header = (struct dnscrypt_query_header *)sldns_buffer_begin(buffer);
|
||||
for (i = 0U; i < dnscenv->signed_certs_count; i++) {
|
||||
if(!certs[i].keypair)
|
||||
continue;
|
||||
if (memcmp(certs[i].magic_query, dnscrypt_header->magic_query,
|
||||
DNSCRYPT_MAGIC_HEADER_LEN) == 0) {
|
||||
return &certs[i];
|
||||
@@ -804,6 +815,7 @@ dnsc_parse_keys(struct dnsc_env *env, struct config_file *cfg)
|
||||
sizeof *env->keypairs);
|
||||
env->certs = sodium_allocarray(env->signed_certs_count,
|
||||
sizeof *env->certs);
|
||||
memset(env->certs, 0, env->signed_certs_count * sizeof(*env->certs));
|
||||
|
||||
cert_id = 0U;
|
||||
keypair_id = 0U;
|
||||
@@ -830,7 +842,14 @@ dnsc_parse_keys(struct dnsc_env *env, struct config_file *cfg)
|
||||
if(memcmp(current_keypair->crypt_publickey,
|
||||
env->signed_certs[c].server_publickey,
|
||||
crypto_box_PUBLICKEYBYTES) == 0) {
|
||||
dnsccert *current_cert = &env->certs[cert_id++];
|
||||
dnsccert* current_cert;
|
||||
if(cert_id >= env->signed_certs_count) {
|
||||
log_err("dnscrypt: secret key %s matches a cert that "
|
||||
"is already bound to another key (duplicate "
|
||||
"dnscrypt-secret-key?)", head->str);
|
||||
return -1;
|
||||
}
|
||||
current_cert = &env->certs[cert_id++];
|
||||
found_cert = 1;
|
||||
current_cert->keypair = current_keypair;
|
||||
memcpy(current_cert->magic_query,
|
||||
@@ -912,12 +931,13 @@ dnsc_handle_curved_request(struct dnsc_env* dnscenv,
|
||||
}
|
||||
|
||||
int
|
||||
dnsc_handle_uncurved_request(struct comm_reply *repinfo)
|
||||
dnsc_handle_uncurved_request(struct comm_reply *repinfo,
|
||||
struct sldns_buffer* buffer)
|
||||
{
|
||||
if(!repinfo->c->dnscrypt) {
|
||||
return 1;
|
||||
}
|
||||
sldns_buffer_copy(repinfo->c->dnscrypt_buffer, repinfo->c->buffer);
|
||||
sldns_buffer_copy(repinfo->c->dnscrypt_buffer, buffer);
|
||||
if(!repinfo->is_dnscrypted) {
|
||||
return 1;
|
||||
}
|
||||
@@ -963,12 +983,19 @@ dnsc_create(void)
|
||||
int
|
||||
dnsc_apply_cfg(struct dnsc_env *env, struct config_file *cfg)
|
||||
{
|
||||
int nkeys;
|
||||
if(dnsc_parse_certs(env, cfg) <= 0) {
|
||||
fatal_exit("dnsc_apply_cfg: no cert file loaded");
|
||||
}
|
||||
if(dnsc_parse_keys(env, cfg) <= 0) {
|
||||
nkeys = dnsc_parse_keys(env, cfg);
|
||||
if(nkeys <= 0) {
|
||||
fatal_exit("dnsc_apply_cfg: no key file loaded");
|
||||
}
|
||||
if((size_t)nkeys < env->signed_certs_count) {
|
||||
fatal_exit("dnsc_apply_cfg: %u dnscrypt-provider-cert file(s) have no "
|
||||
"matching dnscrypt-secret-key",
|
||||
(unsigned)(env->signed_certs_count - (size_t)nkeys));
|
||||
}
|
||||
randombytes_buf(env->hash_key, sizeof env->hash_key);
|
||||
env->provider_name = cfg->dnscrypt_provider;
|
||||
|
||||
|
||||
+2
-1
@@ -128,7 +128,8 @@ int dnsc_handle_curved_request(struct dnsc_env* dnscenv,
|
||||
* \return 0 in case of failure.
|
||||
*/
|
||||
|
||||
int dnsc_handle_uncurved_request(struct comm_reply *repinfo);
|
||||
int dnsc_handle_uncurved_request(struct comm_reply *repinfo,
|
||||
struct sldns_buffer* buffer);
|
||||
|
||||
/**
|
||||
* Computes the size of the shared secret cache entry.
|
||||
|
||||
+38
-19
@@ -176,26 +176,29 @@ dt_create(struct config_file* cfg)
|
||||
env->dtio = dt_io_thread_create();
|
||||
if(!env->dtio) {
|
||||
log_err("malloc failure");
|
||||
free(env);
|
||||
dt_delete(env);
|
||||
return NULL;
|
||||
}
|
||||
if(!dt_io_thread_apply_cfg(env->dtio, cfg)) {
|
||||
dt_io_thread_delete(env->dtio);
|
||||
free(env);
|
||||
dt_delete(env);
|
||||
return NULL;
|
||||
}
|
||||
if(!dt_apply_cfg(env, cfg)) {
|
||||
dt_delete(env);
|
||||
return NULL;
|
||||
}
|
||||
dt_apply_cfg(env, cfg);
|
||||
return env;
|
||||
}
|
||||
|
||||
static void
|
||||
static int
|
||||
dt_apply_identity(struct dt_env *env, struct config_file *cfg)
|
||||
{
|
||||
char buf[MAXHOSTNAMELEN+1];
|
||||
if (!cfg->dnstap_send_identity) {
|
||||
free(env->identity);
|
||||
env->identity = NULL;
|
||||
return;
|
||||
env->len_identity = 0;
|
||||
return 1;
|
||||
}
|
||||
free(env->identity);
|
||||
if (cfg->dnstap_identity == NULL || cfg->dnstap_identity[0] == 0) {
|
||||
@@ -203,36 +206,49 @@ dt_apply_identity(struct dt_env *env, struct config_file *cfg)
|
||||
buf[MAXHOSTNAMELEN] = 0;
|
||||
env->identity = strdup(buf);
|
||||
} else {
|
||||
fatal_exit("dt_apply_identity: gethostname() failed");
|
||||
log_err("dt_apply_identity: gethostname() failed: %s",
|
||||
strerror(errno));
|
||||
env->identity = NULL;
|
||||
env->len_identity = 0;
|
||||
return 0;
|
||||
}
|
||||
} else {
|
||||
env->identity = strdup(cfg->dnstap_identity);
|
||||
}
|
||||
if (env->identity == NULL)
|
||||
fatal_exit("dt_apply_identity: strdup() failed");
|
||||
if (env->identity == NULL) {
|
||||
log_err("dt_apply_identity: strdup() failed");
|
||||
env->len_identity = 0;
|
||||
return 0;
|
||||
}
|
||||
env->len_identity = (unsigned int)strlen(env->identity);
|
||||
verbose(VERB_OPS, "dnstap identity field set to \"%s\"",
|
||||
env->identity);
|
||||
return 1;
|
||||
}
|
||||
|
||||
static void
|
||||
static int
|
||||
dt_apply_version(struct dt_env *env, struct config_file *cfg)
|
||||
{
|
||||
if (!cfg->dnstap_send_version) {
|
||||
free(env->version);
|
||||
env->version = NULL;
|
||||
return;
|
||||
env->len_version = 0;
|
||||
return 1;
|
||||
}
|
||||
free(env->version);
|
||||
if (cfg->dnstap_version == NULL || cfg->dnstap_version[0] == 0)
|
||||
env->version = strdup(PACKAGE_STRING);
|
||||
else
|
||||
env->version = strdup(cfg->dnstap_version);
|
||||
if (env->version == NULL)
|
||||
fatal_exit("dt_apply_version: strdup() failed");
|
||||
if (env->version == NULL) {
|
||||
log_err("dt_apply_version: strdup() failed");
|
||||
env->len_version = 0;
|
||||
return 0;
|
||||
}
|
||||
env->len_version = (unsigned int)strlen(env->version);
|
||||
verbose(VERB_OPS, "dnstap version field set to \"%s\"",
|
||||
env->version);
|
||||
return 1;
|
||||
}
|
||||
|
||||
void
|
||||
@@ -276,15 +292,18 @@ dt_apply_logcfg(struct dt_env *env, struct config_file *cfg)
|
||||
lock_basic_unlock(&env->sample_lock);
|
||||
}
|
||||
|
||||
void
|
||||
int
|
||||
dt_apply_cfg(struct dt_env *env, struct config_file *cfg)
|
||||
{
|
||||
if (!cfg->dnstap)
|
||||
return;
|
||||
return 1;
|
||||
|
||||
dt_apply_identity(env, cfg);
|
||||
dt_apply_version(env, cfg);
|
||||
dt_apply_logcfg(env, cfg);
|
||||
if(!dt_apply_identity(env, cfg))
|
||||
return 0;
|
||||
if(!dt_apply_version(env, cfg))
|
||||
return 0;
|
||||
return 1;
|
||||
}
|
||||
|
||||
int
|
||||
@@ -542,7 +561,7 @@ dt_msg_send_outside_query(struct dt_env *env,
|
||||
qflags = sldns_buffer_read_u16_at(qmsg, 2);
|
||||
|
||||
/* type */
|
||||
if (qflags & BIT_RD) {
|
||||
if ((qflags & BIT_RD)) {
|
||||
if (!env->log_forwarder_query_messages)
|
||||
return;
|
||||
dt_msg_init(env, &dm, DNSTAP__MESSAGE__TYPE__FORWARDER_QUERY);
|
||||
@@ -599,7 +618,7 @@ dt_msg_send_outside_response(struct dt_env *env,
|
||||
qflags = ntohs(qflags);
|
||||
|
||||
/* type */
|
||||
if (qflags & BIT_RD) {
|
||||
if ((qflags & BIT_RD)) {
|
||||
if (!env->log_forwarder_response_messages)
|
||||
return;
|
||||
dt_msg_init(env, &dm, DNSTAP__MESSAGE__TYPE__FORWARDER_RESPONSE);
|
||||
|
||||
+2
-2
@@ -102,9 +102,9 @@ dt_create(struct config_file* cfg);
|
||||
* Apply config settings.
|
||||
* @param env: dnstap environment object.
|
||||
* @param cfg: new config settings.
|
||||
* @return false on failure.
|
||||
*/
|
||||
void
|
||||
dt_apply_cfg(struct dt_env *env, struct config_file *cfg);
|
||||
int dt_apply_cfg(struct dt_env *env, struct config_file *cfg);
|
||||
|
||||
/**
|
||||
* Apply config settings for log enable for message types.
|
||||
|
||||
+35
-4
@@ -18,10 +18,41 @@ AC_DEFUN([dt_DNSTAP],
|
||||
[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!])
|
||||
fi
|
||||
AC_PATH_PROG([PROTOC], [protoc])
|
||||
# 'protoc-c' is deprecated. We use 'protoc' instead. If it can not be
|
||||
# found, try 'protoc-c'.
|
||||
if test -z "$PROTOC"; then
|
||||
AC_PATH_PROG([PROTOC_C], [protoc-c])
|
||||
else
|
||||
PROTOC_C="$PROTOC"
|
||||
fi
|
||||
if test -z "$PROTOC_C"; then
|
||||
AC_MSG_ERROR([[The protoc or protoc-c program was not found. It is needed for dnstap, use --disable-dnstap, or install protobuf-c to provide protoc or protoc-c]])
|
||||
fi
|
||||
|
||||
# Check for protoc-gen-c plugin
|
||||
AC_PATH_PROG([PROTOC_GEN_C], [protoc-gen-c])
|
||||
if test -z "$PROTOC_GEN_C"; then
|
||||
AC_MSG_ERROR([[The protoc-gen-c plugin was not found. It is needed for dnstap, use --disable-dnstap, or install protobuf-c-compiler to provide protoc-gen-c]])
|
||||
fi
|
||||
|
||||
# Test that protoc-gen-c actually works
|
||||
AC_MSG_CHECKING([if protoc-gen-c plugin works])
|
||||
cat > conftest.proto << EOF
|
||||
syntax = "proto2";
|
||||
message TestMessage {
|
||||
optional string test_field = 1;
|
||||
}
|
||||
EOF
|
||||
if $PROTOC_C --c_out=. conftest.proto >/dev/null 2>&1; then
|
||||
AC_MSG_RESULT([yes])
|
||||
rm -f conftest.proto conftest.pb-c.c conftest.pb-c.h
|
||||
else
|
||||
AC_MSG_RESULT([no])
|
||||
rm -f conftest.proto conftest.pb-c.c conftest.pb-c.h
|
||||
AC_MSG_ERROR([[The protoc-gen-c plugin is not working properly. Please ensure protobuf-c-compiler is properly installed]])
|
||||
fi
|
||||
|
||||
AC_ARG_WITH([protobuf-c],
|
||||
AS_HELP_STRING([--with-protobuf-c=path], [Path where protobuf-c is installed, for dnstap]),
|
||||
[
|
||||
|
||||
+1
-1
@@ -98,7 +98,7 @@ message Policy {
|
||||
// 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.
|
||||
// the Response Policy Zone in wire format.
|
||||
optional bytes rule = 2;
|
||||
|
||||
// action: the policy action taken in response to the
|
||||
|
||||
+16
-2
@@ -448,6 +448,9 @@ int dt_io_thread_apply_cfg(struct dt_io_thread* dtio, struct config_file *cfg)
|
||||
dtio->tls_use_sni = cfg->tls_use_sni;
|
||||
#endif /* HAVE_SSL */
|
||||
}
|
||||
#ifdef HAVE_GETTID
|
||||
dtio->thread_tid_log = cfg->log_thread_id;
|
||||
#endif
|
||||
return 1;
|
||||
}
|
||||
|
||||
@@ -1509,7 +1512,7 @@ void dtio_output_cb(int ATTR_UNUSED(fd), short bits, void* arg)
|
||||
}
|
||||
#endif
|
||||
|
||||
if((bits&UB_EV_READ || dtio->ssl_brief_write)) {
|
||||
if((bits&UB_EV_READ) || dtio->ssl_brief_write) {
|
||||
#ifdef HAVE_SSL
|
||||
if(dtio->ssl_brief_write)
|
||||
(void)dtio_disable_brief_write(dtio);
|
||||
@@ -2130,7 +2133,18 @@ static void* dnstap_io(void* arg)
|
||||
struct dt_io_thread* dtio = (struct dt_io_thread*)arg;
|
||||
time_t secs = 0;
|
||||
struct timeval now;
|
||||
log_thread_set(&dtio->threadnum);
|
||||
const char name[16] = "unbound/dnstap"; /* seems to be the safest size
|
||||
between different OSes */
|
||||
|
||||
#if defined(HAVE_GETTID) && !defined(THREADS_DISABLED)
|
||||
dtio->thread_tid = gettid();
|
||||
if(dtio->thread_tid_log)
|
||||
log_thread_set(&dtio->thread_tid);
|
||||
else
|
||||
#endif
|
||||
log_thread_set(&dtio->threadnum);
|
||||
|
||||
ub_thread_setname(ub_thread_self(), name);
|
||||
|
||||
/* setup */
|
||||
verbose(VERB_ALGO, "start dnstap io thread");
|
||||
|
||||
@@ -131,6 +131,12 @@ struct dt_io_thread {
|
||||
struct dt_io_list_item* io_list_iter;
|
||||
/** thread id, of the io thread */
|
||||
ub_thread_type tid;
|
||||
#ifdef HAVE_GETTID
|
||||
/** thread tid, the LWP id */
|
||||
pid_t thread_tid;
|
||||
/** if logging should include the LWP id */
|
||||
int thread_tid_log;
|
||||
#endif
|
||||
/** if the io processing has started */
|
||||
int started;
|
||||
/** ssl context for the io thread, for tls connections. type SSL_CTX* */
|
||||
|
||||
@@ -330,7 +330,7 @@ static struct tap_socket* tap_socket_new_tcpaccept(char* ip,
|
||||
/** create new socket (unconnected, not base-added), or NULL malloc fail */
|
||||
static struct tap_socket* tap_socket_new_tlsaccept(char* ip,
|
||||
void (*ev_cb)(int, short, void*), void* data, char* server_key,
|
||||
char* server_cert, char* verifypem)
|
||||
char* server_cert, char* verifypem, char* tls_protocols)
|
||||
{
|
||||
struct tap_socket* s = calloc(1, sizeof(*s));
|
||||
if(!s) {
|
||||
@@ -347,7 +347,7 @@ static struct tap_socket* tap_socket_new_tlsaccept(char* ip,
|
||||
s->ev_cb = ev_cb;
|
||||
s->data = data;
|
||||
s->sslctx = listen_sslctx_create(server_key, server_cert, verifypem,
|
||||
NULL, NULL, 0, 0, 0);
|
||||
NULL, NULL, 0, 0, 0, tls_protocols);
|
||||
if(!s->sslctx) {
|
||||
log_err("could not create ssl context");
|
||||
free(s->ip);
|
||||
@@ -1261,13 +1261,13 @@ static void setup_tcp_list(struct main_tap_data* maindata,
|
||||
/** setup tls accept sockets */
|
||||
static void setup_tls_list(struct main_tap_data* maindata,
|
||||
struct config_strlist_head* tls_list, char* server_key,
|
||||
char* server_cert, char* verifypem)
|
||||
char* server_cert, char* verifypem, char* tls_protocols)
|
||||
{
|
||||
struct config_strlist* item;
|
||||
for(item = tls_list->first; item; item = item->next) {
|
||||
struct tap_socket* s;
|
||||
s = tap_socket_new_tlsaccept(item->str, &dtio_mainfdcallback,
|
||||
maindata, server_key, server_cert, verifypem);
|
||||
maindata, server_key, server_cert, verifypem, tls_protocols);
|
||||
if(!s) fatal_exit("out of memory");
|
||||
if(!tap_socket_list_insert(&maindata->acceptlist, s))
|
||||
fatal_exit("out of memory");
|
||||
@@ -1300,7 +1300,7 @@ static void
|
||||
setup_and_run(struct config_strlist_head* local_list,
|
||||
struct config_strlist_head* tcp_list,
|
||||
struct config_strlist_head* tls_list, char* server_key,
|
||||
char* server_cert, char* verifypem)
|
||||
char* server_cert, char* verifypem, char* tls_protocols)
|
||||
{
|
||||
time_t secs = 0;
|
||||
struct timeval now;
|
||||
@@ -1326,7 +1326,7 @@ setup_and_run(struct config_strlist_head* local_list,
|
||||
setup_local_list(maindata, local_list);
|
||||
setup_tcp_list(maindata, tcp_list);
|
||||
setup_tls_list(maindata, tls_list, server_key, server_cert,
|
||||
verifypem);
|
||||
verifypem, tls_protocols);
|
||||
if(!tap_socket_list_addevs(maindata->acceptlist, base))
|
||||
fatal_exit("could not setup accept events");
|
||||
if(verbosity) log_info("start of service");
|
||||
@@ -1462,6 +1462,8 @@ int main(int argc, char** argv)
|
||||
struct config_strlist_head tcp_list;
|
||||
struct config_strlist_head tls_list;
|
||||
char* server_key = NULL, *server_cert = NULL, *verifypem = NULL;
|
||||
|
||||
char* tls_protocols = "TLSv1.2 TLSv1.3";
|
||||
#ifdef USE_WINSOCK
|
||||
WSADATA wsa_data;
|
||||
if(WSAStartup(MAKEWORD(2,2), &wsa_data) != 0) {
|
||||
@@ -1561,17 +1563,25 @@ int main(int argc, char** argv)
|
||||
#else
|
||||
OPENSSL_init_crypto(OPENSSL_INIT_ADD_ALL_CIPHERS
|
||||
| OPENSSL_INIT_ADD_ALL_DIGESTS
|
||||
| OPENSSL_INIT_LOAD_CRYPTO_STRINGS, NULL);
|
||||
| OPENSSL_INIT_LOAD_CRYPTO_STRINGS
|
||||
# if defined(OPENSSL_INIT_NO_LOAD_CONFIG) && defined(UB_ON_WINDOWS)
|
||||
| OPENSSL_INIT_NO_LOAD_CONFIG
|
||||
# endif
|
||||
, NULL);
|
||||
#endif
|
||||
#if OPENSSL_VERSION_NUMBER < 0x10100000 || !defined(HAVE_OPENSSL_INIT_SSL)
|
||||
(void)SSL_library_init();
|
||||
#else
|
||||
(void)OPENSSL_init_ssl(OPENSSL_INIT_LOAD_SSL_STRINGS, NULL);
|
||||
(void)OPENSSL_init_ssl(OPENSSL_INIT_LOAD_SSL_STRINGS
|
||||
# if defined(OPENSSL_INIT_NO_LOAD_CONFIG) && defined(UB_ON_WINDOWS)
|
||||
| OPENSSL_INIT_NO_LOAD_CONFIG
|
||||
# endif
|
||||
, NULL);
|
||||
#endif
|
||||
#endif /* HAVE_SSL */
|
||||
}
|
||||
setup_and_run(&local_list, &tcp_list, &tls_list, server_key,
|
||||
server_cert, verifypem);
|
||||
server_cert, verifypem, tls_protocols);
|
||||
config_delstrlist(local_list.first);
|
||||
config_delstrlist(tcp_list.first);
|
||||
config_delstrlist(tls_list.first);
|
||||
@@ -1649,7 +1659,8 @@ struct outbound_entry* worker_send_query(
|
||||
socklen_t ATTR_UNUSED(addrlen), uint8_t* ATTR_UNUSED(zone),
|
||||
size_t ATTR_UNUSED(zonelen), int ATTR_UNUSED(tcp_upstream),
|
||||
int ATTR_UNUSED(ssl_upstream), char* ATTR_UNUSED(tls_auth_name),
|
||||
struct module_qstate* ATTR_UNUSED(q), int* ATTR_UNUSED(was_ratelimited))
|
||||
struct module_qstate* ATTR_UNUSED(q), int* ATTR_UNUSED(was_ratelimited),
|
||||
int* ATTR_UNUSED(ratelimit_incremented))
|
||||
{
|
||||
log_assert(0);
|
||||
return 0;
|
||||
@@ -1683,7 +1694,8 @@ struct outbound_entry* libworker_send_query(
|
||||
socklen_t ATTR_UNUSED(addrlen), uint8_t* ATTR_UNUSED(zone),
|
||||
size_t ATTR_UNUSED(zonelen), int ATTR_UNUSED(tcp_upstream),
|
||||
int ATTR_UNUSED(ssl_upstream), char* ATTR_UNUSED(tls_auth_name),
|
||||
struct module_qstate* ATTR_UNUSED(q), int* ATTR_UNUSED(was_ratelimited))
|
||||
struct module_qstate* ATTR_UNUSED(q), int* ATTR_UNUSED(was_ratelimited),
|
||||
int* ATTR_UNUSED(ratelimit_incremented))
|
||||
{
|
||||
log_assert(0);
|
||||
return 0;
|
||||
@@ -1725,6 +1737,11 @@ void libworker_event_done_cb(void* ATTR_UNUSED(arg), int ATTR_UNUSED(rcode),
|
||||
log_assert(0);
|
||||
}
|
||||
|
||||
void libworker_alloc_cleanup(void* ATTR_UNUSED(arg))
|
||||
{
|
||||
log_assert(0);
|
||||
}
|
||||
|
||||
int context_query_cmp(const void* ATTR_UNUSED(a), const void* ATTR_UNUSED(b))
|
||||
{
|
||||
log_assert(0);
|
||||
|
||||
+1425
-22
File diff suppressed because it is too large
Load Diff
+3
-3
@@ -13,7 +13,7 @@ If you're not using DNSSEC then you may remove "validator".
|
||||
|
||||
2. The "dns64-prefix" directive indicates your DNS64 prefix. For example:
|
||||
|
||||
dns64-prefix: 64:FF9B::/96
|
||||
dns64-prefix: 64:ff9b::/96
|
||||
|
||||
The prefix must be a /96 or shorter.
|
||||
|
||||
@@ -42,9 +42,9 @@ To enable NAT64 in Unbound, add to unbound.conf's "server" section:
|
||||
do-nat64: yes
|
||||
|
||||
The NAT64 prefix defaults to the DNS64 prefix, which in turn defaults to the
|
||||
standard 64:FF9B::/96 prefix. You can reconfigure it with:
|
||||
standard 64:ff9b::/96 prefix. You can reconfigure it with:
|
||||
|
||||
nat64-prefix: 64:FF9B::/96
|
||||
nat64-prefix: 64:ff9b::/96
|
||||
|
||||
To test NAT64 operation, pick a domain that only has IPv4 reachability for its
|
||||
nameservers and try resolving any names in that domain.
|
||||
|
||||
@@ -0,0 +1,21 @@
|
||||
After Unbound 1.23.0, the source of the man pages is in reStructuredText format.
|
||||
|
||||
This helps with the online documentation at https://unbound.docs.nlnetlabs.nl
|
||||
and makes it easier to maintain and contribute to the documentation.
|
||||
|
||||
The templated man pages (*.in) are still part of the code repository as to not
|
||||
alter current procedures that could be in place by users/packagers.
|
||||
|
||||
These man pages (*.in) are still the ones being used when
|
||||
configuring/installing Unbound.
|
||||
Packagers/users do not have to generate any man pages themselves, this is done
|
||||
by the core developers during development and upon releasing new versions.
|
||||
|
||||
The templated man pages (*.in) are generated by Sphinx (used for the online
|
||||
documentation).
|
||||
The online documentation has its own repository at
|
||||
https://github.com/NLnetLabs/unbound-manual.
|
||||
|
||||
In that README.md (https://github.com/NLnetLabs/unbound-manual/README.md)
|
||||
there are further simple instructions on how to generate the templated man
|
||||
pages there and update them in this repository.
|
||||
+69
-25
@@ -54,7 +54,7 @@ server:
|
||||
# interface: 192.0.2.153
|
||||
# interface: 192.0.2.154
|
||||
# interface: 192.0.2.154@5003
|
||||
# interface: 2001:DB8::5
|
||||
# interface: 2001:db8::5
|
||||
# interface: eth0@5003
|
||||
|
||||
# enable this feature to copy the source address of queries to reply.
|
||||
@@ -72,12 +72,12 @@ server:
|
||||
# server from by ip-address. If none, the default (all) interface
|
||||
# is used. Specify every interface on a 'outgoing-interface:' line.
|
||||
# outgoing-interface: 192.0.2.153
|
||||
# outgoing-interface: 2001:DB8::5
|
||||
# outgoing-interface: 2001:DB8::6
|
||||
# outgoing-interface: 2001:db8::5
|
||||
# outgoing-interface: 2001:db8::6
|
||||
|
||||
# Specify a netblock to use remainder 64 bits as random bits for
|
||||
# upstream queries. Uses freebind option (Linux).
|
||||
# outgoing-interface: 2001:DB8::/64
|
||||
# outgoing-interface: 2001:db8::/64
|
||||
# Also (Linux:) ip -6 addr add 2001:db8::/64 dev lo
|
||||
# And: ip -6 route add local 2001:db8::/64 dev lo
|
||||
# And set prefer-ip6: yes to use the ip6 randomness from a netblock.
|
||||
@@ -116,8 +116,8 @@ server:
|
||||
# so-rcvbuf: 0
|
||||
|
||||
# buffer size for UDP port 53 outgoing (SO_SNDBUF socket option).
|
||||
# 0 is system default. Use 4m to handle spikes on very busy servers.
|
||||
# so-sndbuf: 0
|
||||
# 0 is system default. Set larger to handle spikes on very busy servers.
|
||||
# so-sndbuf: 4m
|
||||
|
||||
# use SO_REUSEPORT to distribute queries over threads.
|
||||
# at extreme load it could be better to turn it off to distribute even.
|
||||
@@ -163,7 +163,7 @@ server:
|
||||
# msg-cache-slabs: 4
|
||||
|
||||
# the number of queries that a thread gets to service.
|
||||
# num-queries-per-thread: 1024
|
||||
# num-queries-per-thread: 2048
|
||||
|
||||
# if very busy, 50% queries run to completion, 50% get timeout in msec
|
||||
# jostle-timeout: 200
|
||||
@@ -193,9 +193,16 @@ server:
|
||||
# Limit on number of CNAME, DNAME records for incoming packets.
|
||||
# iter-scrub-cname: 11
|
||||
|
||||
# Limit on number of RRSIGs for an RRset for incoming packets.
|
||||
# iter-scrub-rrsig: 8
|
||||
|
||||
# Limit on upstream queries for an incoming query and its recursion.
|
||||
# max-global-quota: 200
|
||||
|
||||
# Should the scrubber remove promiscuous NS from positive answers,
|
||||
# protects against poison attempts.
|
||||
# iter-scrub-promiscuous: yes
|
||||
|
||||
# msec for waiting for an unknown server to reply. Increase if you
|
||||
# are behind a slow satellite link, to eg. 1128.
|
||||
# unknown-server-time-limit: 376
|
||||
@@ -279,7 +286,7 @@ server:
|
||||
# do-ip6: yes
|
||||
|
||||
# If running unbound on an IPv6-only host, domains that only have
|
||||
# IPv4 servers would become unresolveable. If NAT64 is available in
|
||||
# IPv4 servers would become unresolvable. If NAT64 is available in
|
||||
# the network, unbound can use NAT64 to reach these servers with
|
||||
# the following option. This is NOT needed for enabling DNS64 on a
|
||||
# system that has IPv4 connectivity.
|
||||
@@ -375,7 +382,7 @@ server:
|
||||
# interface-action: 192.0.2.153 allow
|
||||
# interface-action: 192.0.2.154 allow
|
||||
# interface-action: 192.0.2.154@5003 allow
|
||||
# interface-action: 2001:DB8::5 allow
|
||||
# interface-action: 2001:db8::5 allow
|
||||
# interface-action: eth0@5003 allow
|
||||
|
||||
# Similar to 'access-control-tag:' but for interfaces.
|
||||
@@ -492,6 +499,10 @@ server:
|
||||
# print log lines that say why queries return SERVFAIL to clients.
|
||||
# log-servfail: no
|
||||
|
||||
# log system-wide Linux thread ID, insted of Unbound's internal thread
|
||||
# counter. Only on Linux and only when threads are available.
|
||||
# log-thread-id: no
|
||||
|
||||
# the pid file. Can be an absolute path outside of chroot/work dir.
|
||||
# pidfile: "@UNBOUND_PIDFILE@"
|
||||
|
||||
@@ -654,7 +665,7 @@ server:
|
||||
# or, just before the iterator).
|
||||
# module-config: "validator iterator"
|
||||
|
||||
# File with trusted keys, kept uptodate using RFC5011 probes,
|
||||
# File with trusted keys, kept up-to-date using RFC5011 probes,
|
||||
# initial file like trust-anchor-file, then it stores metadata.
|
||||
# Use several entries, one per domain name, to track multiple zones.
|
||||
#
|
||||
@@ -714,7 +725,7 @@ server:
|
||||
# val-max-restart: 5
|
||||
|
||||
# Should additional section of secure message also be kept clean of
|
||||
# unsecure data. Useful to shield the users of this validator from
|
||||
# non-secure data. Useful to shield the users of this validator from
|
||||
# potential bogus data in the additional section. All unsigned data
|
||||
# in the additional section is removed from secure messages.
|
||||
# val-clean-additional: yes
|
||||
@@ -752,6 +763,7 @@ server:
|
||||
# serve-expired-ttl-reset: no
|
||||
#
|
||||
# TTL value to use when replying with expired data.
|
||||
# Capped by the original TTL of the record.
|
||||
# serve-expired-reply-ttl: 30
|
||||
#
|
||||
# Time in milliseconds before replying to the client with expired data.
|
||||
@@ -887,6 +899,10 @@ server:
|
||||
# that name
|
||||
# o block_a resolves all records normally but returns
|
||||
# NODATA for A queries and ignores local data for that name
|
||||
# o block_aaaa similarly to block_a, resolves all records normally but
|
||||
# returns NODATA for AAAA queries and ignores local data for that name
|
||||
# o block_a_wdata like block_a but uses local data if present.
|
||||
# o block_aaaa_wdata like block_aaaa but uses local data if present.
|
||||
# o always_null returns 0.0.0.0 or ::0 for any name in the zone.
|
||||
# o noview breaks out of that view towards global local-zones.
|
||||
#
|
||||
@@ -921,6 +937,22 @@ server:
|
||||
# add a netblock specific override to a localzone, with zone type
|
||||
# local-zone-override: "example.com" 192.0.2.0/24 refuse
|
||||
|
||||
# Action to apply when the IP address in an AAAA or A RR in the answer
|
||||
# section of a response matches the specified IP netblock.
|
||||
# Requires use of the respip module.
|
||||
# response-ip: 192.0.2.0/24 redirect
|
||||
|
||||
# Redirect as specified by the "resource record string" when the IP
|
||||
# address in an AAAA or A RR in the answer section of a response
|
||||
# matches the specified IP netblock.
|
||||
# Requires use of the respip module.
|
||||
# response-ip-data: 192.0.2.0/24 "example. A 192.0.2.1"
|
||||
|
||||
# Apply tag(s) when the IP address in an AAAA or A RR in the answer
|
||||
# section of a response matches the specified IP netblock.
|
||||
# Requires use of the respip module.
|
||||
# response-ip-tag: 192.0.2.0/24 "tag1 tag2"
|
||||
|
||||
# service clients over TLS (on the TCP sockets) with plain DNS inside
|
||||
# the TLS stream, and over HTTPS using HTTP/2 as specified in RFC8484.
|
||||
# Give the certificate to use and private key.
|
||||
@@ -931,21 +963,22 @@ server:
|
||||
# https-port: 443
|
||||
# quic-port: 853
|
||||
|
||||
# Also serve tls on these port numbers (eg. 443, ...), by listing
|
||||
# tls-additional-port: portno for each of the port numbers.
|
||||
|
||||
# cipher setting for TLSv1.2
|
||||
# tls-ciphers: "DHE-RSA-AES256-GCM-SHA384:DHE-RSA-AES128-GCM-SHA256:ECDHE-RSA-AES256-GCM-SHA384:ECDHE-RSA-AES128-GCM-SHA256:DHE-RSA-AES256-SHA256:DHE-RSA-AES128-SHA256:ECDHE-RSA-AES256-SHA384:ECDHE-RSA-AES128-SHA256"
|
||||
# cipher setting for TLSv1.3
|
||||
# tls-ciphersuites: "TLS_AES_128_GCM_SHA256:TLS_AES_128_CCM_8_SHA256:TLS_AES_128_CCM_SHA256:TLS_AES_256_GCM_SHA384:TLS_CHACHA20_POLY1305_SHA256"
|
||||
|
||||
# Pad responses to padded queries received over TLS
|
||||
# pad-responses: yes
|
||||
|
||||
# Padded responses will be padded to the closest multiple of this size.
|
||||
# pad-responses-block-size: 468
|
||||
|
||||
# Use the SNI extension for TLS connections. Default is yes.
|
||||
# Changing the value requires a reload.
|
||||
# Changing the value requires a restart.
|
||||
# tls-use-sni: yes
|
||||
|
||||
# TLS protocols.
|
||||
# Changing the value requires a restart.
|
||||
# tls-protocols: "TLSv1.2 TLSv1.3"
|
||||
|
||||
# Add the secret file for TLS Session Ticket.
|
||||
# Secret file must be 80 bytes of random data.
|
||||
# First key use to encrypt and decrypt TLS session tickets.
|
||||
@@ -966,15 +999,18 @@ server:
|
||||
# and on other systems, the default openssl certificates
|
||||
# tls-system-cert: no
|
||||
|
||||
# Pad responses to padded queries received over TLS
|
||||
# pad-responses: yes
|
||||
|
||||
# Padded responses will be padded to the closest multiple of this size.
|
||||
# pad-responses-block-size: 468
|
||||
|
||||
# Pad queries over TLS upstreams
|
||||
# pad-queries: yes
|
||||
|
||||
# Padded queries will be padded to the closest multiple of this size.
|
||||
# pad-queries-block-size: 128
|
||||
|
||||
# Also serve tls on these port numbers (eg. 443, ...), by listing
|
||||
# tls-additional-port: portno for each of the port numbers.
|
||||
|
||||
# HTTP endpoint to provide DNS-over-HTTPS service on.
|
||||
# http-endpoint: "/dns-query"
|
||||
|
||||
@@ -1255,12 +1291,16 @@ remote-control:
|
||||
# zonemd-check: no
|
||||
# zonemd-reject-absence: no
|
||||
# zonefile: "example.org.zone"
|
||||
# max-transfer-size: 0
|
||||
# max-transfer-time: 0
|
||||
|
||||
|
||||
# Views
|
||||
# Create named views. Name must be unique. Map views to requests using
|
||||
# the access-control-view option. Views can contain zero or more local-zone
|
||||
# and local-data options. Options from matching views will override global
|
||||
# options. Global options will be used if no matching view is found.
|
||||
# Create named views. Name must be unique.
|
||||
# Map views to requests using the access-control-view/interface-view options.
|
||||
# Views can contain zero or more local-zone and local-data options.
|
||||
# Options from matching views will override global options.
|
||||
# Global options will be used if no matching view is found.
|
||||
# With view-first yes, it will try to answer using the global local-zone and
|
||||
# local-data elements if there is no view specific match.
|
||||
# view:
|
||||
@@ -1268,6 +1308,8 @@ remote-control:
|
||||
# local-zone: "example.com" redirect
|
||||
# local-data: "example.com A 192.0.2.3"
|
||||
# local-data-ptr: "192.0.2.3 www.example.com"
|
||||
# response-ip: 192.0.2.0/24 redirect
|
||||
# response-ip-data: 192.0.2.0/24 "example. A 192.0.2.1"
|
||||
# view-first: no
|
||||
# view:
|
||||
# name: "anotherview"
|
||||
@@ -1418,3 +1460,5 @@ remote-control:
|
||||
# rpz-signal-nxdomain-ra: no
|
||||
# for-downstream: no
|
||||
# tags: "example"
|
||||
# max-transfer-size: 0
|
||||
# max-transfer-time: 0
|
||||
|
||||
+330
-343
@@ -1,335 +1,306 @@
|
||||
.TH "libunbound" "3" "@date@" "NLnet Labs" "unbound @version@"
|
||||
.\"
|
||||
.\" libunbound.3 -- unbound library functions manual
|
||||
.\"
|
||||
.\" Copyright (c) 2007, NLnet Labs. All rights reserved.
|
||||
.\"
|
||||
.\" See LICENSE for the license.
|
||||
.\"
|
||||
.\"
|
||||
.SH "NAME"
|
||||
.B libunbound,
|
||||
.B unbound.h,
|
||||
.B ub_ctx,
|
||||
.B ub_result,
|
||||
.B ub_callback_type,
|
||||
.B ub_ctx_create,
|
||||
.B ub_ctx_delete,
|
||||
.B ub_ctx_set_option,
|
||||
.B ub_ctx_get_option,
|
||||
.B ub_ctx_config,
|
||||
.B ub_ctx_set_fwd,
|
||||
.B ub_ctx_set_stub,
|
||||
.B ub_ctx_set_tls,
|
||||
.B ub_ctx_resolvconf,
|
||||
.B ub_ctx_hosts,
|
||||
.B ub_ctx_add_ta,
|
||||
.B ub_ctx_add_ta_autr,
|
||||
.B ub_ctx_add_ta_file,
|
||||
.B ub_ctx_trustedkeys,
|
||||
.B ub_ctx_debugout,
|
||||
.B ub_ctx_debuglevel,
|
||||
.B ub_ctx_async,
|
||||
.B ub_poll,
|
||||
.B ub_wait,
|
||||
.B ub_fd,
|
||||
.B ub_process,
|
||||
.B ub_resolve,
|
||||
.B ub_resolve_async,
|
||||
.B ub_cancel,
|
||||
.B ub_resolve_free,
|
||||
.B ub_strerror,
|
||||
.B ub_ctx_print_local_zones,
|
||||
.B ub_ctx_zone_add,
|
||||
.B ub_ctx_zone_remove,
|
||||
.B ub_ctx_data_add,
|
||||
.B ub_ctx_data_remove
|
||||
\- Unbound DNS validating resolver @version@ functions.
|
||||
.SH "SYNOPSIS"
|
||||
.B #include <unbound.h>
|
||||
.LP
|
||||
\fIstruct ub_ctx *\fR
|
||||
\fBub_ctx_create\fR(\fIvoid\fR);
|
||||
.LP
|
||||
\fIvoid\fR
|
||||
\fBub_ctx_delete\fR(\fIstruct ub_ctx*\fR ctx);
|
||||
.LP
|
||||
\fIint\fR
|
||||
\fBub_ctx_set_option\fR(\fIstruct ub_ctx*\fR ctx, \fIchar*\fR opt, \fIchar*\fR val);
|
||||
.LP
|
||||
\fIint\fR
|
||||
\fBub_ctx_get_option\fR(\fIstruct ub_ctx*\fR ctx, \fIchar*\fR opt, \fIchar**\fR val);
|
||||
.LP
|
||||
\fIint\fR
|
||||
\fBub_ctx_config\fR(\fIstruct ub_ctx*\fR ctx, \fIchar*\fR fname);
|
||||
.LP
|
||||
\fIint\fR
|
||||
\fBub_ctx_set_fwd\fR(\fIstruct ub_ctx*\fR ctx, \fIchar*\fR addr);
|
||||
.LP
|
||||
\fIint\fR
|
||||
\fBub_ctx_set_stub\fR(\fIstruct ub_ctx*\fR ctx, \fIchar*\fR zone,
|
||||
\fIchar*\fR addr,
|
||||
.br
|
||||
\fIint\fR isprime);
|
||||
.LP
|
||||
\fIint\fR
|
||||
\fBub_ctx_set_tls\fR(\fIstruct ub_ctx*\fR ctx, \fIint\fR tls);
|
||||
.LP
|
||||
\fIint\fR
|
||||
\fBub_ctx_resolvconf\fR(\fIstruct ub_ctx*\fR ctx, \fIchar*\fR fname);
|
||||
.LP
|
||||
\fIint\fR
|
||||
\fBub_ctx_hosts\fR(\fIstruct ub_ctx*\fR ctx, \fIchar*\fR fname);
|
||||
.LP
|
||||
\fIint\fR
|
||||
\fBub_ctx_add_ta\fR(\fIstruct ub_ctx*\fR ctx, \fIchar*\fR ta);
|
||||
.LP
|
||||
\fIint\fR
|
||||
\fBub_ctx_add_ta_autr\fR(\fIstruct ub_ctx*\fR ctx, \fIchar*\fR fname);
|
||||
.LP
|
||||
\fIint\fR
|
||||
\fBub_ctx_add_ta_file\fR(\fIstruct ub_ctx*\fR ctx, \fIchar*\fR fname);
|
||||
.LP
|
||||
\fIint\fR
|
||||
\fBub_ctx_trustedkeys\fR(\fIstruct ub_ctx*\fR ctx, \fIchar*\fR fname);
|
||||
.LP
|
||||
\fIint\fR
|
||||
\fBub_ctx_debugout\fR(\fIstruct ub_ctx*\fR ctx, \fIFILE*\fR out);
|
||||
.LP
|
||||
\fIint\fR
|
||||
\fBub_ctx_debuglevel\fR(\fIstruct ub_ctx*\fR ctx, \fIint\fR d);
|
||||
.LP
|
||||
\fIint\fR
|
||||
\fBub_ctx_async\fR(\fIstruct ub_ctx*\fR ctx, \fIint\fR dothread);
|
||||
.LP
|
||||
\fIint\fR
|
||||
\fBub_poll\fR(\fIstruct ub_ctx*\fR ctx);
|
||||
.LP
|
||||
\fIint\fR
|
||||
\fBub_wait\fR(\fIstruct ub_ctx*\fR ctx);
|
||||
.LP
|
||||
\fIint\fR
|
||||
\fBub_fd\fR(\fIstruct ub_ctx*\fR ctx);
|
||||
.LP
|
||||
\fIint\fR
|
||||
\fBub_process\fR(\fIstruct ub_ctx*\fR ctx);
|
||||
.LP
|
||||
\fIint\fR
|
||||
\fBub_resolve\fR(\fIstruct ub_ctx*\fR ctx, \fIchar*\fR name,
|
||||
.br
|
||||
\fIint\fR rrtype, \fIint\fR rrclass, \fIstruct ub_result**\fR result);
|
||||
.LP
|
||||
\fIint\fR
|
||||
\fBub_resolve_async\fR(\fIstruct ub_ctx*\fR ctx, \fIchar*\fR name,
|
||||
.br
|
||||
\fIint\fR rrtype, \fIint\fR rrclass, \fIvoid*\fR mydata,
|
||||
.br
|
||||
\fIub_callback_type\fR callback, \fIint*\fR async_id);
|
||||
.LP
|
||||
\fIint\fR
|
||||
\fBub_cancel\fR(\fIstruct ub_ctx*\fR ctx, \fIint\fR async_id);
|
||||
.LP
|
||||
\fIvoid\fR
|
||||
\fBub_resolve_free\fR(\fIstruct ub_result*\fR result);
|
||||
.LP
|
||||
\fIconst char *\fR
|
||||
\fBub_strerror\fR(\fIint\fR err);
|
||||
.LP
|
||||
\fIint\fR
|
||||
\fBub_ctx_print_local_zones\fR(\fIstruct ub_ctx*\fR ctx);
|
||||
.LP
|
||||
\fIint\fR
|
||||
\fBub_ctx_zone_add\fR(\fIstruct ub_ctx*\fR ctx, \fIchar*\fR zone_name, \fIchar*\fR zone_type);
|
||||
.LP
|
||||
\fIint\fR
|
||||
\fBub_ctx_zone_remove\fR(\fIstruct ub_ctx*\fR ctx, \fIchar*\fR zone_name);
|
||||
.LP
|
||||
\fIint\fR
|
||||
\fBub_ctx_data_add\fR(\fIstruct ub_ctx*\fR ctx, \fIchar*\fR data);
|
||||
.LP
|
||||
\fIint\fR
|
||||
\fBub_ctx_data_remove\fR(\fIstruct ub_ctx*\fR ctx, \fIchar*\fR data);
|
||||
.SH "DESCRIPTION"
|
||||
.B Unbound
|
||||
is an implementation of a DNS resolver, that does caching and
|
||||
DNSSEC validation. This is the library API, for using the \-lunbound library.
|
||||
The server daemon is described in \fIunbound\fR(8).
|
||||
The library works independent from a running unbound server, and
|
||||
can be used to convert hostnames to ip addresses, and back,
|
||||
and obtain other information from the DNS. The library performs public\-key
|
||||
validation of results with DNSSEC.
|
||||
.P
|
||||
The library uses a variable of type \fIstruct ub_ctx\fR to keep context
|
||||
between calls. The user must maintain it, creating it with
|
||||
.B ub_ctx_create
|
||||
and deleting it with
|
||||
.B ub_ctx_delete\fR.
|
||||
It can be created and deleted at any time. Creating it anew removes any
|
||||
previous configuration (such as trusted keys) and clears any cached results.
|
||||
.P
|
||||
The functions are thread\-safe, and a context can be used in a threaded (as
|
||||
well as in a non\-threaded) environment. Also resolution (and validation)
|
||||
can be performed blocking and non\-blocking (also called asynchronous).
|
||||
The async method returns from the call immediately, so that processing
|
||||
can go on, while the results become available later.
|
||||
.P
|
||||
.\" Man page generated from reStructuredText.
|
||||
.
|
||||
.
|
||||
.nr rst2man-indent-level 0
|
||||
.
|
||||
.de1 rstReportMargin
|
||||
\\$1 \\n[an-margin]
|
||||
level \\n[rst2man-indent-level]
|
||||
level margin: \\n[rst2man-indent\\n[rst2man-indent-level]]
|
||||
-
|
||||
\\n[rst2man-indent0]
|
||||
\\n[rst2man-indent1]
|
||||
\\n[rst2man-indent2]
|
||||
..
|
||||
.de1 INDENT
|
||||
.\" .rstReportMargin pre:
|
||||
. RS \\$1
|
||||
. nr rst2man-indent\\n[rst2man-indent-level] \\n[an-margin]
|
||||
. nr rst2man-indent-level +1
|
||||
.\" .rstReportMargin post:
|
||||
..
|
||||
.de UNINDENT
|
||||
. RE
|
||||
.\" indent \\n[an-margin]
|
||||
.\" old: \\n[rst2man-indent\\n[rst2man-indent-level]]
|
||||
.nr rst2man-indent-level -1
|
||||
.\" new: \\n[rst2man-indent\\n[rst2man-indent-level]]
|
||||
.in \\n[rst2man-indent\\n[rst2man-indent-level]]u
|
||||
..
|
||||
.TH "LIBUNBOUND" "3" "@date@" "@version@" "Unbound"
|
||||
.SH NAME
|
||||
libunbound \- Unbound DNS validating resolver @version@ functions.
|
||||
.SH SYNOPSIS
|
||||
.sp
|
||||
\fB#include <unbound.h>\fP
|
||||
.sp
|
||||
struct ub_ctx * \fBub_ctx_create\fP(void);
|
||||
.sp
|
||||
void \fBub_ctx_delete\fP(struct ub_ctx* ctx);
|
||||
.sp
|
||||
int \fBub_ctx_set_option\fP(struct ub_ctx* ctx, char* opt, char* val);
|
||||
.sp
|
||||
int \fBub_ctx_get_option\fP(struct ub_ctx* ctx, char* opt, char** val);
|
||||
.sp
|
||||
int \fBub_ctx_config\fP(struct ub_ctx* ctx, char* fname);
|
||||
.sp
|
||||
int \fBub_ctx_set_fwd\fP(struct ub_ctx* ctx, char* addr);
|
||||
.INDENT 0.0
|
||||
.TP
|
||||
int \fBub_ctx_set_stub\fP(struct ub_ctx* ctx, char* zone, char* addr,
|
||||
int isprime);
|
||||
.UNINDENT
|
||||
.sp
|
||||
int \fBub_ctx_set_tls\fP(struct ub_ctx* ctx, int tls);
|
||||
.sp
|
||||
int \fBub_ctx_resolvconf\fP(struct ub_ctx* ctx, char* fname);
|
||||
.sp
|
||||
int \fBub_ctx_hosts\fP(struct ub_ctx* ctx, char* fname);
|
||||
.sp
|
||||
int \fBub_ctx_add_ta\fP(struct ub_ctx* ctx, char* ta);
|
||||
.sp
|
||||
int \fBub_ctx_add_ta_autr\fP(struct ub_ctx* ctx, char* fname);
|
||||
.sp
|
||||
int \fBub_ctx_add_ta_file\fP(struct ub_ctx* ctx, char* fname);
|
||||
.sp
|
||||
int \fBub_ctx_trustedkeys\fP(struct ub_ctx* ctx, char* fname);
|
||||
.sp
|
||||
int \fBub_ctx_debugout\fP(struct ub_ctx* ctx, FILE* out);
|
||||
.sp
|
||||
int \fBub_ctx_debuglevel\fP(struct ub_ctx* ctx, int d);
|
||||
.sp
|
||||
int \fBub_ctx_async\fP(struct ub_ctx* ctx, int dothread);
|
||||
.sp
|
||||
int \fBub_poll\fP(struct ub_ctx* ctx);
|
||||
.sp
|
||||
int \fBub_wait\fP(struct ub_ctx* ctx);
|
||||
.sp
|
||||
int \fBub_fd\fP(struct ub_ctx* ctx);
|
||||
.sp
|
||||
int \fBub_process\fP(struct ub_ctx* ctx);
|
||||
.INDENT 0.0
|
||||
.TP
|
||||
int \fBub_resolve\fP(struct ub_ctx* ctx, char* name,
|
||||
int rrtype, int rrclass, struct ub_result** result);
|
||||
.TP
|
||||
int \fBub_resolve_async\fP(struct ub_ctx* ctx, char* name,
|
||||
int rrtype, int rrclass, void* mydata,
|
||||
ub_callback_type* callback, int* async_id);
|
||||
.UNINDENT
|
||||
.sp
|
||||
int \fBub_cancel\fP(struct ub_ctx* ctx, int async_id);
|
||||
.sp
|
||||
void \fBub_resolve_free\fP(struct ub_result* result);
|
||||
.sp
|
||||
const char * \fBub_strerror\fP(int err);
|
||||
.sp
|
||||
int \fBub_ctx_print_local_zones\fP(struct ub_ctx* ctx);
|
||||
.sp
|
||||
int \fBub_ctx_zone_add\fP(struct ub_ctx* ctx, char* zone_name, char* zone_type);
|
||||
.sp
|
||||
int \fBub_ctx_zone_remove\fP(struct ub_ctx* ctx, char* zone_name);
|
||||
.sp
|
||||
int \fBub_ctx_data_add\fP(struct ub_ctx* ctx, char* data);
|
||||
.sp
|
||||
int \fBub_ctx_data_remove\fP(struct ub_ctx* ctx, char* data);
|
||||
.SH DESCRIPTION
|
||||
.sp
|
||||
Unbound is an implementation of a DNS resolver, that does caching and DNSSEC
|
||||
validation.
|
||||
This is the library API, for using the \fB\-lunbound\fP library.
|
||||
The server daemon is described in \fI\%unbound(8)\fP\&.
|
||||
The library works independent from a running unbound server, and can be used to
|
||||
convert hostnames to ip addresses, and back, and obtain other information from
|
||||
the DNS.
|
||||
The library performs public\-key validation of results with DNSSEC.
|
||||
.sp
|
||||
The library uses a variable of type \fIstruct ub_ctx\fP to keep context between
|
||||
calls.
|
||||
The user must maintain it, creating it with \fBub_ctx_create\fP and deleting it
|
||||
with \fBub_ctx_delete\fP\&.
|
||||
It can be created and deleted at any time.
|
||||
Creating it anew removes any previous configuration (such as trusted keys) and
|
||||
clears any cached results.
|
||||
.sp
|
||||
The functions are thread\-safe, and a context can be used in a threaded (as well
|
||||
as in a non\-threaded) environment.
|
||||
Also resolution (and validation) can be performed blocking and non\-blocking
|
||||
(also called asynchronous).
|
||||
The async method returns from the call immediately, so that processing can go
|
||||
on, while the results become available later.
|
||||
.sp
|
||||
The functions are discussed in turn below.
|
||||
.SH "FUNCTIONS"
|
||||
.TP
|
||||
.SH FUNCTIONS
|
||||
.INDENT 0.0
|
||||
.TP
|
||||
.B ub_ctx_create
|
||||
Create a new context, initialised with defaults.
|
||||
The information from /etc/resolv.conf and /etc/hosts is not utilised
|
||||
by default. Use
|
||||
.B ub_ctx_resolvconf
|
||||
and
|
||||
.B ub_ctx_hosts
|
||||
to read them.
|
||||
Before you call this, use the openssl functions CRYPTO_set_id_callback and
|
||||
CRYPTO_set_locking_callback to set up asynchronous operation if you use
|
||||
lib openssl (the application calls these functions once for initialisation).
|
||||
Openssl 1.0.0 or later uses the CRYPTO_THREADID_set_callback function.
|
||||
The information from \fB/etc/resolv.conf\fP and \fB/etc/hosts\fP is
|
||||
not utilised by default.
|
||||
Use \fBub_ctx_resolvconf\fP and \fBub_ctx_hosts\fP to read them.
|
||||
Before you call this, use the openssl functions
|
||||
\fBCRYPTO_set_id_callback\fP and \fBCRYPTO_set_locking_callback\fP to set
|
||||
up asynchronous operation if you use lib openssl (the application calls
|
||||
these functions once for initialisation).
|
||||
Openssl 1.0.0 or later uses the \fBCRYPTO_THREADID_set_callback\fP
|
||||
function.
|
||||
.TP
|
||||
.B ub_ctx_delete
|
||||
Delete validation context and free associated resources.
|
||||
Outstanding async queries are killed and callbacks are not called for them.
|
||||
Outstanding async queries are killed and callbacks are not called for
|
||||
them.
|
||||
.TP
|
||||
.B ub_ctx_set_option
|
||||
A power\-user interface that lets you specify one of the options from the
|
||||
config file format, see \fIunbound.conf\fR(5). Not all options are
|
||||
relevant. For some specific options, such as adding trust anchors, special
|
||||
routines exist. Pass the option name with the trailing ':'.
|
||||
A power\-user interface that lets you specify one of the options from
|
||||
the config file format, see \fI\%unbound.conf(5)\fP\&.
|
||||
Not all options are relevant.
|
||||
For some specific options, such as adding trust anchors, special
|
||||
routines exist.
|
||||
Pass the option name with the trailing \fB\(aq:\(aq\fP\&.
|
||||
.TP
|
||||
.B ub_ctx_get_option
|
||||
A power\-user interface that gets an option value. Some options cannot be
|
||||
gotten, and others return a newline separated list. Pass the option name
|
||||
without trailing ':'. The returned value must be free(2)d by the caller.
|
||||
A power\-user interface that gets an option value.
|
||||
Some options cannot be gotten, and others return a newline separated
|
||||
list.
|
||||
Pass the option name without trailing \fB\(aq:\(aq\fP\&.
|
||||
The returned value must be free(2)d by the caller.
|
||||
.TP
|
||||
.B ub_ctx_config
|
||||
A power\-user interface that lets you specify an unbound config file, see
|
||||
\fIunbound.conf\fR(5), which is read for configuration. Not all options are
|
||||
relevant. For some specific options, such as adding trust anchors, special
|
||||
routines exist. This function is thread\-safe only if a single instance of
|
||||
ub_ctx* exists in the application. If several instances exist the
|
||||
application has to ensure that ub_ctx_config is not called in parallel by
|
||||
the different instances.
|
||||
A power\-user interface that lets you specify an unbound config file,
|
||||
see \fI\%unbound.conf(5)\fP, which is read for
|
||||
configuration.
|
||||
Not all options are relevant.
|
||||
For some specific options, such as adding trust anchors, special
|
||||
routines exist.
|
||||
This function is thread\-safe only if a single instance of \fBub_ctx\fP*
|
||||
exists in the application.
|
||||
If several instances exist the application has to ensure that
|
||||
\fBub_ctx_config\fP is not called in parallel by the different instances.
|
||||
.TP
|
||||
.B ub_ctx_set_fwd
|
||||
Set machine to forward DNS queries to, the caching resolver to use.
|
||||
IP4 or IP6 address. Forwards all DNS requests to that machine, which
|
||||
is expected to run a recursive resolver. If the proxy is not
|
||||
DNSSEC capable, validation may fail. Can be called several times, in
|
||||
that case the addresses are used as backup servers.
|
||||
At this time it is only possible to set configuration before the
|
||||
first resolve is done.
|
||||
Set machine to forward DNS queries to, the caching resolver to use.
|
||||
IP4 or IP6 address.
|
||||
Forwards all DNS requests to that machine, which is expected to run a
|
||||
recursive resolver.
|
||||
If the proxy is not DNSSEC capable, validation may fail.
|
||||
Can be called several times, in that case the addresses are used as
|
||||
backup servers.
|
||||
At this time it is only possible to set configuration before the first
|
||||
resolve is done.
|
||||
.TP
|
||||
.B ub_ctx_set_stub
|
||||
Set a stub zone, authoritative dns servers to use for a particular zone.
|
||||
IP4 or IP6 address. If the address is NULL the stub entry is removed.
|
||||
Set isprime true if you configure root hints with it. Otherwise similar to
|
||||
the stub zone item from unbound's config file. Can be called several times,
|
||||
for different zones, or to add multiple addresses for a particular zone.
|
||||
At this time it is only possible to set configuration before the
|
||||
first resolve is done.
|
||||
Set a stub zone, authoritative dns servers to use for a particular
|
||||
zone.
|
||||
IP4 or IP6 address.
|
||||
If the address is NULL the stub entry is removed.
|
||||
Set isprime true if you configure root hints with it.
|
||||
Otherwise similar to the stub zone item from unbound\(aqs config file.
|
||||
Can be called several times, for different zones, or to add multiple
|
||||
addresses for a particular zone.
|
||||
At this time it is only possible to set configuration before the first
|
||||
resolve is done.
|
||||
.TP
|
||||
.B ub_ctx_set_tls
|
||||
Enable DNS over TLS (DoT) for machines set with
|
||||
.B ub_ctx_set_fwd.
|
||||
At this time it is only possible to set configuration before the
|
||||
first resolve is done.
|
||||
Enable DNS over TLS (DoT) for machines set with \fBub_ctx_set_fwd\fP\&.
|
||||
At this time it is only possible to set configuration before the first
|
||||
resolve is done.
|
||||
.TP
|
||||
.B ub_ctx_resolvconf
|
||||
By default the root servers are queried and full resolver mode is used, but
|
||||
you can use this call to read the list of nameservers to use from the
|
||||
filename given.
|
||||
Usually "/etc/resolv.conf". Uses those nameservers as caching proxies.
|
||||
By default the root servers are queried and full resolver mode is used,
|
||||
but you can use this call to read the list of nameservers to use from
|
||||
the filename given.
|
||||
Usually \fB\(dq/etc/resolv.conf\(dq\fP\&.
|
||||
Uses those nameservers as caching proxies.
|
||||
If they do not support DNSSEC, validation may fail.
|
||||
Only nameservers are picked up, the searchdomain, ndots and other
|
||||
settings from \fIresolv.conf\fR(5) are ignored.
|
||||
If fname NULL is passed, "/etc/resolv.conf" is used (if on Windows,
|
||||
the system\-wide configured nameserver is picked instead).
|
||||
At this time it is only possible to set configuration before the
|
||||
first resolve is done.
|
||||
settings from \fIresolv.conf(5)\fP are ignored.
|
||||
If fname NULL is passed, \fB\(dq/etc/resolv.conf\(dq\fP is used (if on
|
||||
Windows, the system\-wide configured nameserver is picked instead).
|
||||
At this time it is only possible to set configuration before the first
|
||||
resolve is done.
|
||||
.TP
|
||||
.B ub_ctx_hosts
|
||||
Read list of hosts from the filename given.
|
||||
Usually "/etc/hosts". When queried for, these addresses are not marked
|
||||
DNSSEC secure. If fname NULL is passed, "/etc/hosts" is used
|
||||
(if on Windows, etc/hosts from WINDIR is picked instead).
|
||||
At this time it is only possible to set configuration before the
|
||||
first resolve is done.
|
||||
Usually \fB\(dq/etc/hosts\(dq\fP\&.
|
||||
When queried for, these addresses are not marked DNSSEC secure.
|
||||
If fname NULL is passed, \fB\(dq/etc/hosts\(dq\fP is used (if on Windows,
|
||||
\fBetc/hosts\fP from WINDIR is picked instead).
|
||||
At this time it is only possible to set configuration before the first
|
||||
resolve is done.
|
||||
.TP
|
||||
.B
|
||||
ub_ctx_add_ta
|
||||
.B ub_ctx_add_ta
|
||||
Add a trust anchor to the given context.
|
||||
At this time it is only possible to add trusted keys before the
|
||||
first resolve is done.
|
||||
At this time it is only possible to add trusted keys before the first
|
||||
resolve is done.
|
||||
The format is a string, similar to the zone\-file format,
|
||||
[domainname] [type] [rdata contents]. Both DS and DNSKEY records are accepted.
|
||||
\fB[domainname]\fP \fB[type]\fP \fB[rdata contents]\fP\&.
|
||||
Both DS and DNSKEY records are accepted.
|
||||
.TP
|
||||
.B ub_ctx_add_ta_autr
|
||||
Add filename with automatically tracked trust anchor to the given context.
|
||||
Pass name of a file with the managed trust anchor. You can create this
|
||||
file with \fIunbound\-anchor\fR(8) for the root anchor. You can also
|
||||
create it with an initial file with one line with a DNSKEY or DS record.
|
||||
Add filename with automatically tracked trust anchor to the given
|
||||
context.
|
||||
Pass name of a file with the managed trust anchor.
|
||||
You can create this file with
|
||||
\fI\%unbound\-anchor(8)\fP for the root anchor.
|
||||
You can also create it with an initial file with one line with a DNSKEY
|
||||
or DS record.
|
||||
If the file is writable, it is updated when the trust anchor changes.
|
||||
At this time it is only possible to add trusted keys before the
|
||||
first resolve is done.
|
||||
At this time it is only possible to add trusted keys before the first
|
||||
resolve is done.
|
||||
.TP
|
||||
.B ub_ctx_add_ta_file
|
||||
Add trust anchors to the given context.
|
||||
Pass name of a file with DS and DNSKEY records in zone file format.
|
||||
At this time it is only possible to add trusted keys before the
|
||||
first resolve is done.
|
||||
At this time it is only possible to add trusted keys before the first
|
||||
resolve is done.
|
||||
.TP
|
||||
.B ub_ctx_trustedkeys
|
||||
Add trust anchors to the given context.
|
||||
Pass the name of a bind\-style config file with trusted\-keys{}.
|
||||
At this time it is only possible to add trusted keys before the
|
||||
first resolve is done.
|
||||
Pass the name of a bind\-style config file with \fBtrusted\-keys{}\fP\&.
|
||||
At this time it is only possible to add trusted keys before the first
|
||||
resolve is done.
|
||||
.TP
|
||||
.B ub_ctx_debugout
|
||||
Set debug and error log output to the given stream. Pass NULL to disable
|
||||
output. Default is stderr. File\-names or using syslog can be enabled
|
||||
using config options, this routine is for using your own stream.
|
||||
Set debug and error log output to the given stream.
|
||||
Pass NULL to disable output.
|
||||
Default is stderr.
|
||||
File\-names or using syslog can be enabled using config options, this
|
||||
routine is for using your own stream.
|
||||
.TP
|
||||
.B ub_ctx_debuglevel
|
||||
Set debug verbosity for the context. Output is directed to stderr.
|
||||
Set debug verbosity for the context.
|
||||
Output is directed to stderr.
|
||||
Higher debug level gives more output.
|
||||
.TP
|
||||
.B ub_ctx_async
|
||||
Set a context behaviour for asynchronous action.
|
||||
if set to true, enables threading and a call to
|
||||
.B ub_resolve_async
|
||||
if set to true, enables threading and a call to \fBub_resolve_async\fP
|
||||
creates a thread to handle work in the background.
|
||||
If false, a process is forked to handle work in the background.
|
||||
Changes to this setting after
|
||||
.B ub_resolve_async
|
||||
calls have been made have no effect (delete and re\-create the context
|
||||
to change).
|
||||
Changes to this setting after \fBub_resolve_async\fP calls have been made
|
||||
have no effect (delete and re\-create the context to change).
|
||||
.TP
|
||||
.B ub_poll
|
||||
Poll a context to see if it has any new results.
|
||||
Do not poll in a loop, instead extract the fd below to poll for readiness,
|
||||
and then check, or wait using the wait routine.
|
||||
Do not poll in a loop, instead extract the \fBfd\fP below to poll for
|
||||
readiness, and then check, or wait using the wait routine.
|
||||
Returns 0 if nothing to read, or nonzero if a result is available.
|
||||
If nonzero, call
|
||||
.B ub_process
|
||||
to do callbacks.
|
||||
If nonzero, call \fBub_process\fP to do callbacks.
|
||||
.TP
|
||||
.B ub_wait
|
||||
Wait for a context to finish with results. Calls
|
||||
.B ub_process
|
||||
after the wait for you. After the wait, there are no more outstanding
|
||||
asynchronous queries.
|
||||
Wait for a context to finish with results.
|
||||
Calls \fBub_process\fP after the wait for you.
|
||||
After the wait, there are no more outstanding asynchronous queries.
|
||||
.TP
|
||||
.B ub_fd
|
||||
Get file descriptor. Wait for it to become readable, at this point
|
||||
answers are returned from the asynchronous validating resolver.
|
||||
Then call the \fBub_process\fR to continue processing.
|
||||
Get file descriptor.
|
||||
Wait for it to become readable, at this point answers are returned from
|
||||
the asynchronous validating resolver.
|
||||
Then call the \fBub_process\fP to continue processing.
|
||||
.TP
|
||||
.B ub_process
|
||||
Call this routine to continue processing results from the validating
|
||||
resolver (when the fd becomes readable).
|
||||
resolver (when the \fBfd\fP becomes readable).
|
||||
Will perform necessary callbacks.
|
||||
.TP
|
||||
.B ub_resolve
|
||||
@@ -340,95 +311,111 @@ The result structure is newly allocated with the resulting data.
|
||||
.TP
|
||||
.B ub_resolve_async
|
||||
Perform asynchronous resolution and validation of the target name.
|
||||
Arguments mean the same as for \fBub_resolve\fR except no
|
||||
data is returned immediately, instead a callback is called later.
|
||||
The callback receives a copy of the mydata pointer, that you can use to pass
|
||||
information to the callback. The callback type is a function pointer to
|
||||
a function declared as
|
||||
.IP
|
||||
void my_callback_function(void* my_arg, int err,
|
||||
.br
|
||||
struct ub_result* result);
|
||||
.IP
|
||||
The async_id is returned so you can (at your option) decide to track it
|
||||
and cancel the request if needed. If you pass a NULL pointer the async_id
|
||||
is not returned.
|
||||
Arguments mean the same as for \fBub_resolve\fP except no data is
|
||||
returned immediately, instead a callback is called later.
|
||||
The callback receives a copy of the mydata pointer, that you can use to
|
||||
pass information to the callback.
|
||||
The callback type is a function pointer to a function declared as:
|
||||
.INDENT 7.0
|
||||
.INDENT 3.5
|
||||
.sp
|
||||
.nf
|
||||
.ft C
|
||||
void my_callback_function(void* my_arg, int err,
|
||||
struct ub_result* result);
|
||||
.ft P
|
||||
.fi
|
||||
.UNINDENT
|
||||
.UNINDENT
|
||||
.sp
|
||||
The \fBasync_id\fP is returned so you can (at your option) decide to
|
||||
track it and cancel the request if needed.
|
||||
If you pass a NULL pointer the \fBasync_id\fP is not returned.
|
||||
.TP
|
||||
.B ub_cancel
|
||||
Cancel an async query in progress. This may return an error if the query
|
||||
does not exist, or the query is already being delivered, in that case you
|
||||
may still get a callback for the query.
|
||||
Cancel an async query in progress.
|
||||
This may return an error if the query does not exist, or the query is
|
||||
already being delivered, in that case you may still get a callback for
|
||||
the query.
|
||||
.TP
|
||||
.B ub_resolve_free
|
||||
Free struct ub_result contents after use.
|
||||
Free struct \fBub_result\fP contents after use.
|
||||
.TP
|
||||
.B ub_strerror
|
||||
Convert error value from one of the unbound library functions
|
||||
to a human readable string.
|
||||
Convert error value from one of the unbound library functions to a
|
||||
human readable string.
|
||||
.TP
|
||||
.B ub_ctx_print_local_zones
|
||||
Debug printout the local authority information to debug output.
|
||||
.TP
|
||||
.B ub_ctx_zone_add
|
||||
Add new zone to local authority info, like local\-zone \fIunbound.conf\fR(5)
|
||||
statement.
|
||||
Add new zone to local authority info, like local\-zone
|
||||
\fI\%unbound.conf(5)\fP statement.
|
||||
.TP
|
||||
.B ub_ctx_zone_remove
|
||||
Delete zone from local authority info.
|
||||
.TP
|
||||
.B ub_ctx_data_add
|
||||
Add resource record data to local authority info, like local\-data
|
||||
\fIunbound.conf\fR(5) statement.
|
||||
\fI\%unbound.conf(5)\fP statement.
|
||||
.TP
|
||||
.B ub_ctx_data_remove
|
||||
Delete local authority data from the name given.
|
||||
.SH "RESULT DATA STRUCTURE"
|
||||
The result of the DNS resolution and validation is returned as
|
||||
\fIstruct ub_result\fR. The result structure contains the following entries.
|
||||
.P
|
||||
.UNINDENT
|
||||
.SH RESULT DATA STRUCTURE
|
||||
.sp
|
||||
The result of the DNS resolution and validation is returned as \fIstruct
|
||||
ub_result\fP\&.
|
||||
The result structure contains the following entries:
|
||||
.INDENT 0.0
|
||||
.INDENT 3.5
|
||||
.sp
|
||||
.nf
|
||||
struct ub_result {
|
||||
char* qname; /* text string, original question */
|
||||
int qtype; /* type code asked for */
|
||||
int qclass; /* class code asked for */
|
||||
char** data; /* array of rdata items, NULL terminated*/
|
||||
int* len; /* array with lengths of rdata items */
|
||||
char* canonname; /* canonical name of result */
|
||||
int rcode; /* additional error code in case of no data */
|
||||
void* answer_packet; /* full network format answer packet */
|
||||
int answer_len; /* length of packet in octets */
|
||||
int havedata; /* true if there is data */
|
||||
int nxdomain; /* true if nodata because name does not exist */
|
||||
int secure; /* true if result is secure */
|
||||
int bogus; /* true if a security failure happened */
|
||||
char* why_bogus; /* string with error if bogus */
|
||||
int was_ratelimited; /* true if the query was ratelimited (SERVFAIL) by unbound */
|
||||
int ttl; /* number of seconds the result is valid */
|
||||
};
|
||||
.ft C
|
||||
struct ub_result {
|
||||
char* qname; /* text string, original question */
|
||||
int qtype; /* type code asked for */
|
||||
int qclass; /* class code asked for */
|
||||
char** data; /* array of rdata items, NULL terminated*/
|
||||
int* len; /* array with lengths of rdata items */
|
||||
char* canonname; /* canonical name of result */
|
||||
int rcode; /* additional error code in case of no data */
|
||||
void* answer_packet; /* full network format answer packet */
|
||||
int answer_len; /* length of packet in octets */
|
||||
int havedata; /* true if there is data */
|
||||
int nxdomain; /* true if nodata because name does not exist */
|
||||
int secure; /* true if result is secure */
|
||||
int bogus; /* true if a security failure happened */
|
||||
char* why_bogus; /* string with error if bogus */
|
||||
int was_ratelimited; /* true if the query was ratelimited (SERVFAIL) by unbound */
|
||||
int ttl; /* number of seconds the result is valid */
|
||||
};
|
||||
.ft P
|
||||
.fi
|
||||
.P
|
||||
If both secure and bogus are false, security was not enabled for the
|
||||
domain of the query. Else, they are not both true, one of them is true.
|
||||
.SH "RETURN VALUES"
|
||||
Many routines return an error code. The value 0 (zero) denotes no error
|
||||
happened. Other values can be passed to
|
||||
.B ub_strerror
|
||||
to obtain a readable error string.
|
||||
.B ub_strerror
|
||||
returns a zero terminated string.
|
||||
.B ub_ctx_create
|
||||
returns NULL on an error (a malloc failure).
|
||||
.B ub_poll
|
||||
returns true if some information may be available, false otherwise.
|
||||
.B ub_fd
|
||||
returns a file descriptor or \-1 on error.
|
||||
.B ub_ctx_config
|
||||
and
|
||||
.B ub_ctx_resolvconf
|
||||
attempt to leave errno informative on a function return with file read failure.
|
||||
.SH "SEE ALSO"
|
||||
\fIunbound.conf\fR(5),
|
||||
\fIunbound\fR(8).
|
||||
.SH "AUTHORS"
|
||||
.B Unbound
|
||||
developers are mentioned in the CREDITS file in the distribution.
|
||||
.UNINDENT
|
||||
.UNINDENT
|
||||
.sp
|
||||
If both secure and bogus are false, security was not enabled for the domain of
|
||||
the query.
|
||||
Else, they are not both true, one of them is true.
|
||||
.SH RETURN VALUES
|
||||
.sp
|
||||
Many routines return an error code.
|
||||
The value 0 (zero) denotes no error happened.
|
||||
Other values can be passed to \fBub_strerror\fP to obtain a readable error
|
||||
string.
|
||||
\fBub_strerror\fP returns a zero terminated string.
|
||||
\fBub_ctx_create\fP returns NULL on an error (a malloc failure).
|
||||
\fBub_poll\fP returns true if some information may be available, false otherwise.
|
||||
\fBub_fd\fP returns a file descriptor or \-1 on error.
|
||||
\fBub_ctx_config\fP and \fBub_ctx_resolvconf\fP attempt to leave errno informative
|
||||
on a function return with file read failure.
|
||||
.SH SEE ALSO
|
||||
.sp
|
||||
\fI\%unbound.conf(5)\fP, \fI\%unbound(8)\fP\&.
|
||||
.SH AUTHOR
|
||||
Unbound developers are mentioned in the CREDITS file in the distribution.
|
||||
.SH COPYRIGHT
|
||||
1999-2026, NLnet Labs
|
||||
.\" Generated by docutils manpage writer.
|
||||
.
|
||||
|
||||
@@ -0,0 +1,491 @@
|
||||
..
|
||||
WHEN EDITING MAKE SURE EACH SENTENCE STARTS ON A NEW LINE
|
||||
|
||||
..
|
||||
IT HELPS RENDERERS TO DO THE RIGHT THING WRT SPACE
|
||||
|
||||
..
|
||||
IT HELPS PEOPLE DIFFING THE CHANGES
|
||||
|
||||
..
|
||||
WHEN EDITING MAKE SURE EACH SENTENCE STARTS ON A NEW LINE
|
||||
|
||||
..
|
||||
IT HELPS RENDERERS TO DO THE RIGHT THING WRT SPACE
|
||||
|
||||
..
|
||||
IT HELPS PEOPLE DIFFING THE CHANGES
|
||||
|
||||
..
|
||||
WHEN EDITING MAKE SURE EACH SENTENCE STARTS ON A NEW LINE
|
||||
|
||||
..
|
||||
IT HELPS RENDERERS TO DO THE RIGHT THING WRT SPACE
|
||||
|
||||
..
|
||||
IT HELPS PEOPLE DIFFING THE CHANGES
|
||||
|
||||
..
|
||||
WHEN EDITING MAKE SURE EACH SENTENCE STARTS ON A NEW LINE
|
||||
|
||||
..
|
||||
IT HELPS RENDERERS TO DO THE RIGHT THING WRT SPACE
|
||||
|
||||
..
|
||||
IT HELPS PEOPLE DIFFING THE CHANGES
|
||||
|
||||
libunbound(3)
|
||||
=============
|
||||
|
||||
Synopsis
|
||||
--------
|
||||
|
||||
.. only:: html
|
||||
|
||||
.. code-block:: c
|
||||
|
||||
#include <unbound.h>
|
||||
|
||||
struct ub_ctx * ub_ctx_create(void);
|
||||
|
||||
void ub_ctx_delete(struct ub_ctx* ctx);
|
||||
|
||||
int ub_ctx_set_option(struct ub_ctx* ctx, char* opt, char* val);
|
||||
|
||||
int ub_ctx_get_option(struct ub_ctx* ctx, char* opt, char** val);
|
||||
|
||||
int ub_ctx_config(struct ub_ctx* ctx, char* fname);
|
||||
|
||||
int ub_ctx_set_fwd(struct ub_ctx* ctx, char* addr);
|
||||
|
||||
int ub_ctx_set_stub(struct ub_ctx* ctx, char* zone, char* addr,
|
||||
int isprime);
|
||||
|
||||
int ub_ctx_set_tls(struct ub_ctx* ctx, int tls);
|
||||
|
||||
int ub_ctx_resolvconf(struct ub_ctx* ctx, char* fname);
|
||||
|
||||
int ub_ctx_hosts(struct ub_ctx* ctx, char* fname);
|
||||
|
||||
int ub_ctx_add_ta(struct ub_ctx* ctx, char* ta);
|
||||
|
||||
int ub_ctx_add_ta_autr(struct ub_ctx* ctx, char* fname);
|
||||
|
||||
int ub_ctx_add_ta_file(struct ub_ctx* ctx, char* fname);
|
||||
|
||||
int ub_ctx_trustedkeys(struct ub_ctx* ctx, char* fname);
|
||||
|
||||
int ub_ctx_debugout(struct ub_ctx* ctx, FILE* out);
|
||||
|
||||
int ub_ctx_debuglevel(struct ub_ctx* ctx, int d);
|
||||
|
||||
int ub_ctx_async(struct ub_ctx* ctx, int dothread);
|
||||
|
||||
int ub_poll(struct ub_ctx* ctx);
|
||||
|
||||
int ub_wait(struct ub_ctx* ctx);
|
||||
|
||||
int ub_fd(struct ub_ctx* ctx);
|
||||
|
||||
int ub_process(struct ub_ctx* ctx);
|
||||
|
||||
int ub_resolve(struct ub_ctx* ctx, char* name, int rrtype,
|
||||
int rrclass, struct ub_result** result);
|
||||
|
||||
int ub_resolve_async(struct ub_ctx* ctx, char* name, int rrtype,
|
||||
int rrclass, void* mydata, ub_callback_type callback,
|
||||
int* async_id);
|
||||
|
||||
int ub_cancel(struct ub_ctx* ctx, int async_id);
|
||||
|
||||
void ub_resolve_free(struct ub_result* result);
|
||||
|
||||
const char * ub_strerror(int err);
|
||||
|
||||
int ub_ctx_print_local_zones(struct ub_ctx* ctx);
|
||||
|
||||
int ub_ctx_zone_add(struct ub_ctx* ctx, char* zone_name, char* zone_type);
|
||||
|
||||
int ub_ctx_zone_remove(struct ub_ctx* ctx, char* zone_name);
|
||||
|
||||
int ub_ctx_data_add(struct ub_ctx* ctx, char* data);
|
||||
|
||||
int ub_ctx_data_remove(struct ub_ctx* ctx, char* data);
|
||||
|
||||
.. only:: man
|
||||
|
||||
**#include <unbound.h>**
|
||||
|
||||
struct ub_ctx \* **ub_ctx_create**\ (void);
|
||||
|
||||
void **ub_ctx_delete**\ (struct ub_ctx\* ctx);
|
||||
|
||||
int **ub_ctx_set_option**\ (struct ub_ctx\* ctx, char\* opt, char\* val);
|
||||
|
||||
int **ub_ctx_get_option**\ (struct ub_ctx\* ctx, char\* opt, char\*\* val);
|
||||
|
||||
int **ub_ctx_config**\ (struct ub_ctx\* ctx, char* fname);
|
||||
|
||||
int **ub_ctx_set_fwd**\ (struct ub_ctx\* ctx, char\* addr);
|
||||
|
||||
int **ub_ctx_set_stub**\ (struct ub_ctx\* ctx, char\* zone, char\* addr,
|
||||
int isprime);
|
||||
|
||||
int **ub_ctx_set_tls**\ (struct ub_ctx\* ctx, int tls);
|
||||
|
||||
int **ub_ctx_resolvconf**\ (struct ub_ctx\* ctx, char\* fname);
|
||||
|
||||
int **ub_ctx_hosts**\ (struct ub_ctx\* ctx, char\* fname);
|
||||
|
||||
int **ub_ctx_add_ta**\ (struct ub_ctx\* ctx, char\* ta);
|
||||
|
||||
int **ub_ctx_add_ta_autr**\ (struct ub_ctx\* ctx, char\* fname);
|
||||
|
||||
int **ub_ctx_add_ta_file**\ (struct ub_ctx\* ctx, char\* fname);
|
||||
|
||||
int **ub_ctx_trustedkeys**\ (struct ub_ctx\* ctx, char\* fname);
|
||||
|
||||
int **ub_ctx_debugout**\ (struct ub_ctx\* ctx, FILE\* out);
|
||||
|
||||
int **ub_ctx_debuglevel**\ (struct ub_ctx\* ctx, int d);
|
||||
|
||||
int **ub_ctx_async**\ (struct ub_ctx\* ctx, int dothread);
|
||||
|
||||
int **ub_poll**\ (struct ub_ctx\* ctx);
|
||||
|
||||
int **ub_wait**\ (struct ub_ctx\* ctx);
|
||||
|
||||
int **ub_fd**\ (struct ub_ctx\* ctx);
|
||||
|
||||
int **ub_process**\ (struct ub_ctx\* ctx);
|
||||
|
||||
int **ub_resolve**\ (struct ub_ctx\* ctx, char\* name,
|
||||
int rrtype, int rrclass, struct ub_result\*\* result);
|
||||
|
||||
int **ub_resolve_async**\ (struct ub_ctx\* ctx, char\* name,
|
||||
int rrtype, int rrclass, void\* mydata,
|
||||
ub_callback_type\* callback, int\* async_id);
|
||||
|
||||
int **ub_cancel**\ (struct ub_ctx\* ctx, int async_id);
|
||||
|
||||
void **ub_resolve_free**\ (struct ub_result\* result);
|
||||
|
||||
const char \* **ub_strerror**\ (int err);
|
||||
|
||||
int **ub_ctx_print_local_zones**\ (struct ub_ctx\* ctx);
|
||||
|
||||
int **ub_ctx_zone_add**\ (struct ub_ctx\* ctx, char\* zone_name, char\* zone_type);
|
||||
|
||||
int **ub_ctx_zone_remove**\ (struct ub_ctx\* ctx, char\* zone_name);
|
||||
|
||||
int **ub_ctx_data_add**\ (struct ub_ctx\* ctx, char\* data);
|
||||
|
||||
int **ub_ctx_data_remove**\ (struct ub_ctx\* ctx, char\* data);
|
||||
|
||||
Description
|
||||
-----------
|
||||
|
||||
Unbound is an implementation of a DNS resolver, that does caching and DNSSEC
|
||||
validation.
|
||||
This is the library API, for using the ``-lunbound`` library.
|
||||
The server daemon is described in :doc:`unbound(8)</manpages/unbound>`.
|
||||
The library works independent from a running unbound server, and can be used to
|
||||
convert hostnames to ip addresses, and back, and obtain other information from
|
||||
the DNS.
|
||||
The library performs public-key validation of results with DNSSEC.
|
||||
|
||||
The library uses a variable of type *struct ub_ctx* to keep context between
|
||||
calls.
|
||||
The user must maintain it, creating it with **ub_ctx_create** and deleting it
|
||||
with **ub_ctx_delete**.
|
||||
It can be created and deleted at any time.
|
||||
Creating it anew removes any previous configuration (such as trusted keys) and
|
||||
clears any cached results.
|
||||
|
||||
The functions are thread-safe, and a context can be used in a threaded (as well
|
||||
as in a non-threaded) environment.
|
||||
Also resolution (and validation) can be performed blocking and non-blocking
|
||||
(also called asynchronous).
|
||||
The async method returns from the call immediately, so that processing can go
|
||||
on, while the results become available later.
|
||||
|
||||
The functions are discussed in turn below.
|
||||
|
||||
Functions
|
||||
---------
|
||||
|
||||
.. glossary::
|
||||
|
||||
ub_ctx_create
|
||||
Create a new context, initialised with defaults.
|
||||
The information from :file:`/etc/resolv.conf` and :file:`/etc/hosts` is
|
||||
not utilised by default.
|
||||
Use **ub_ctx_resolvconf** and **ub_ctx_hosts** to read them.
|
||||
Before you call this, use the openssl functions
|
||||
**CRYPTO_set_id_callback** and **CRYPTO_set_locking_callback** to set
|
||||
up asynchronous operation if you use lib openssl (the application calls
|
||||
these functions once for initialisation).
|
||||
Openssl 1.0.0 or later uses the **CRYPTO_THREADID_set_callback**
|
||||
function.
|
||||
|
||||
ub_ctx_delete
|
||||
Delete validation context and free associated resources.
|
||||
Outstanding async queries are killed and callbacks are not called for
|
||||
them.
|
||||
|
||||
ub_ctx_set_option
|
||||
A power-user interface that lets you specify one of the options from
|
||||
the config file format, see :doc:`unbound.conf(5)</manpages/unbound.conf>`.
|
||||
Not all options are relevant.
|
||||
For some specific options, such as adding trust anchors, special
|
||||
routines exist.
|
||||
Pass the option name with the trailing ``':'``.
|
||||
|
||||
ub_ctx_get_option
|
||||
A power-user interface that gets an option value.
|
||||
Some options cannot be gotten, and others return a newline separated
|
||||
list.
|
||||
Pass the option name without trailing ``':'``.
|
||||
The returned value must be free(2)d by the caller.
|
||||
|
||||
ub_ctx_config
|
||||
A power-user interface that lets you specify an unbound config file,
|
||||
see :doc:`unbound.conf(5)</manpages/unbound.conf>`, which is read for
|
||||
configuration.
|
||||
Not all options are relevant.
|
||||
For some specific options, such as adding trust anchors, special
|
||||
routines exist.
|
||||
This function is thread-safe only if a single instance of **ub_ctx**\*
|
||||
exists in the application.
|
||||
If several instances exist the application has to ensure that
|
||||
**ub_ctx_config** is not called in parallel by the different instances.
|
||||
|
||||
ub_ctx_set_fwd
|
||||
Set machine to forward DNS queries to, the caching resolver to use.
|
||||
IP4 or IP6 address.
|
||||
Forwards all DNS requests to that machine, which is expected to run a
|
||||
recursive resolver.
|
||||
If the proxy is not DNSSEC capable, validation may fail.
|
||||
Can be called several times, in that case the addresses are used as
|
||||
backup servers.
|
||||
At this time it is only possible to set configuration before the first
|
||||
resolve is done.
|
||||
|
||||
ub_ctx_set_stub
|
||||
Set a stub zone, authoritative dns servers to use for a particular
|
||||
zone.
|
||||
IP4 or IP6 address.
|
||||
If the address is NULL the stub entry is removed.
|
||||
Set isprime true if you configure root hints with it.
|
||||
Otherwise similar to the stub zone item from unbound's config file.
|
||||
Can be called several times, for different zones, or to add multiple
|
||||
addresses for a particular zone.
|
||||
At this time it is only possible to set configuration before the first
|
||||
resolve is done.
|
||||
|
||||
ub_ctx_set_tls
|
||||
Enable DNS over TLS (DoT) for machines set with **ub_ctx_set_fwd**.
|
||||
At this time it is only possible to set configuration before the first
|
||||
resolve is done.
|
||||
|
||||
ub_ctx_resolvconf
|
||||
By default the root servers are queried and full resolver mode is used,
|
||||
but you can use this call to read the list of nameservers to use from
|
||||
the filename given.
|
||||
Usually :file:`"/etc/resolv.conf"`.
|
||||
Uses those nameservers as caching proxies.
|
||||
If they do not support DNSSEC, validation may fail.
|
||||
Only nameservers are picked up, the searchdomain, ndots and other
|
||||
settings from *resolv.conf(5)* are ignored.
|
||||
If fname NULL is passed, :file:`"/etc/resolv.conf"` is used (if on
|
||||
Windows, the system-wide configured nameserver is picked instead).
|
||||
At this time it is only possible to set configuration before the first
|
||||
resolve is done.
|
||||
|
||||
ub_ctx_hosts
|
||||
Read list of hosts from the filename given.
|
||||
Usually :file:`"/etc/hosts"`.
|
||||
When queried for, these addresses are not marked DNSSEC secure.
|
||||
If fname NULL is passed, :file:`"/etc/hosts"` is used (if on Windows,
|
||||
:file:`etc/hosts` from WINDIR is picked instead).
|
||||
At this time it is only possible to set configuration before the first
|
||||
resolve is done.
|
||||
|
||||
ub_ctx_add_ta
|
||||
Add a trust anchor to the given context.
|
||||
At this time it is only possible to add trusted keys before the first
|
||||
resolve is done.
|
||||
The format is a string, similar to the zone-file format,
|
||||
**[domainname]** **[type]** **[rdata contents]**.
|
||||
Both DS and DNSKEY records are accepted.
|
||||
|
||||
ub_ctx_add_ta_autr
|
||||
Add filename with automatically tracked trust anchor to the given
|
||||
context.
|
||||
Pass name of a file with the managed trust anchor.
|
||||
You can create this file with
|
||||
:doc:`unbound-anchor(8)</manpages/unbound-anchor>` for the root anchor.
|
||||
You can also create it with an initial file with one line with a DNSKEY
|
||||
or DS record.
|
||||
If the file is writable, it is updated when the trust anchor changes.
|
||||
At this time it is only possible to add trusted keys before the first
|
||||
resolve is done.
|
||||
|
||||
ub_ctx_add_ta_file
|
||||
Add trust anchors to the given context.
|
||||
Pass name of a file with DS and DNSKEY records in zone file format.
|
||||
At this time it is only possible to add trusted keys before the first
|
||||
resolve is done.
|
||||
|
||||
ub_ctx_trustedkeys
|
||||
Add trust anchors to the given context.
|
||||
Pass the name of a bind-style config file with ``trusted-keys{}``.
|
||||
At this time it is only possible to add trusted keys before the first
|
||||
resolve is done.
|
||||
|
||||
ub_ctx_debugout
|
||||
Set debug and error log output to the given stream.
|
||||
Pass NULL to disable output.
|
||||
Default is stderr.
|
||||
File-names or using syslog can be enabled using config options, this
|
||||
routine is for using your own stream.
|
||||
|
||||
ub_ctx_debuglevel
|
||||
Set debug verbosity for the context.
|
||||
Output is directed to stderr.
|
||||
Higher debug level gives more output.
|
||||
|
||||
ub_ctx_async
|
||||
Set a context behaviour for asynchronous action.
|
||||
if set to true, enables threading and a call to **ub_resolve_async**
|
||||
creates a thread to handle work in the background.
|
||||
If false, a process is forked to handle work in the background.
|
||||
Changes to this setting after **ub_resolve_async** calls have been made
|
||||
have no effect (delete and re-create the context to change).
|
||||
|
||||
ub_poll
|
||||
Poll a context to see if it has any new results.
|
||||
Do not poll in a loop, instead extract the **fd** below to poll for
|
||||
readiness, and then check, or wait using the wait routine.
|
||||
Returns 0 if nothing to read, or nonzero if a result is available.
|
||||
If nonzero, call **ub_process** to do callbacks.
|
||||
|
||||
ub_wait
|
||||
Wait for a context to finish with results.
|
||||
Calls **ub_process** after the wait for you.
|
||||
After the wait, there are no more outstanding asynchronous queries.
|
||||
|
||||
ub_fd
|
||||
Get file descriptor.
|
||||
Wait for it to become readable, at this point answers are returned from
|
||||
the asynchronous validating resolver.
|
||||
Then call the **ub_process** to continue processing.
|
||||
|
||||
ub_process
|
||||
Call this routine to continue processing results from the validating
|
||||
resolver (when the **fd** becomes readable).
|
||||
Will perform necessary callbacks.
|
||||
|
||||
ub_resolve
|
||||
Perform resolution and validation of the target name.
|
||||
The name is a domain name in a zero terminated text string.
|
||||
The rrtype and rrclass are DNS type and class codes.
|
||||
The result structure is newly allocated with the resulting data.
|
||||
|
||||
ub_resolve_async
|
||||
Perform asynchronous resolution and validation of the target name.
|
||||
Arguments mean the same as for **ub_resolve** except no data is
|
||||
returned immediately, instead a callback is called later.
|
||||
The callback receives a copy of the mydata pointer, that you can use to
|
||||
pass information to the callback.
|
||||
The callback type is a function pointer to a function declared as:
|
||||
|
||||
.. code-block:: c
|
||||
|
||||
void my_callback_function(void* my_arg, int err,
|
||||
struct ub_result* result);
|
||||
|
||||
The **async_id** is returned so you can (at your option) decide to
|
||||
track it and cancel the request if needed.
|
||||
If you pass a NULL pointer the **async_id** is not returned.
|
||||
|
||||
ub_cancel
|
||||
Cancel an async query in progress.
|
||||
This may return an error if the query does not exist, or the query is
|
||||
already being delivered, in that case you may still get a callback for
|
||||
the query.
|
||||
|
||||
ub_resolve_free
|
||||
Free struct **ub_result** contents after use.
|
||||
|
||||
ub_strerror
|
||||
Convert error value from one of the unbound library functions to a
|
||||
human readable string.
|
||||
|
||||
ub_ctx_print_local_zones
|
||||
Debug printout the local authority information to debug output.
|
||||
|
||||
ub_ctx_zone_add
|
||||
Add new zone to local authority info, like local-zone
|
||||
:doc:`unbound.conf(5)</manpages/unbound.conf>` statement.
|
||||
|
||||
ub_ctx_zone_remove
|
||||
Delete zone from local authority info.
|
||||
|
||||
ub_ctx_data_add
|
||||
Add resource record data to local authority info, like local-data
|
||||
:doc:`unbound.conf(5)</manpages/unbound.conf>` statement.
|
||||
|
||||
ub_ctx_data_remove
|
||||
Delete local authority data from the name given.
|
||||
|
||||
Result Data structure
|
||||
---------------------
|
||||
|
||||
The result of the DNS resolution and validation is returned as *struct
|
||||
ub_result*.
|
||||
The result structure contains the following entries:
|
||||
|
||||
.. code-block:: c
|
||||
|
||||
struct ub_result {
|
||||
char* qname; /* text string, original question */
|
||||
int qtype; /* type code asked for */
|
||||
int qclass; /* class code asked for */
|
||||
char** data; /* array of rdata items, NULL terminated*/
|
||||
int* len; /* array with lengths of rdata items */
|
||||
char* canonname; /* canonical name of result */
|
||||
int rcode; /* additional error code in case of no data */
|
||||
void* answer_packet; /* full network format answer packet */
|
||||
int answer_len; /* length of packet in octets */
|
||||
int havedata; /* true if there is data */
|
||||
int nxdomain; /* true if nodata because name does not exist */
|
||||
int secure; /* true if result is secure */
|
||||
int bogus; /* true if a security failure happened */
|
||||
char* why_bogus; /* string with error if bogus */
|
||||
int was_ratelimited; /* true if the query was ratelimited (SERVFAIL) by unbound */
|
||||
int ttl; /* number of seconds the result is valid */
|
||||
};
|
||||
|
||||
If both secure and bogus are false, security was not enabled for the domain of
|
||||
the query.
|
||||
Else, they are not both true, one of them is true.
|
||||
|
||||
Return Values
|
||||
-------------
|
||||
|
||||
Many routines return an error code.
|
||||
The value 0 (zero) denotes no error happened.
|
||||
Other values can be passed to **ub_strerror** to obtain a readable error
|
||||
string.
|
||||
**ub_strerror** returns a zero terminated string.
|
||||
**ub_ctx_create** returns NULL on an error (a malloc failure).
|
||||
**ub_poll** returns true if some information may be available, false otherwise.
|
||||
**ub_fd** returns a file descriptor or -1 on error.
|
||||
**ub_ctx_config** and **ub_ctx_resolvconf** attempt to leave errno informative
|
||||
on a function return with file read failure.
|
||||
|
||||
See Also
|
||||
--------
|
||||
|
||||
:doc:`unbound.conf(5)</manpages/unbound.conf>`, :doc:`unbound(8)</manpages/unbound>`.
|
||||
+255
-135
@@ -1,189 +1,309 @@
|
||||
.TH "unbound-anchor" "8" "@date@" "NLnet Labs" "unbound @version@"
|
||||
.\"
|
||||
.\" unbound-anchor.8 -- unbound anchor maintenance utility manual
|
||||
.\"
|
||||
.\" Copyright (c) 2008, NLnet Labs. All rights reserved.
|
||||
.\"
|
||||
.\" See LICENSE for the license.
|
||||
.\"
|
||||
.\"
|
||||
.SH "NAME"
|
||||
.B unbound\-anchor
|
||||
\- Unbound anchor utility.
|
||||
.SH "SYNOPSIS"
|
||||
.B unbound\-anchor
|
||||
.RB [ opts ]
|
||||
.SH "DESCRIPTION"
|
||||
.B Unbound\-anchor
|
||||
performs setup or update of the root trust anchor for DNSSEC validation.
|
||||
The program fetches the trust anchor with the method from RFC7958 when
|
||||
regular RFC5011 update fails to bring it up to date.
|
||||
It can be run (as root) from the commandline, or run as part of startup
|
||||
scripts. Before you start the \fIunbound\fR(8) DNS server.
|
||||
.P
|
||||
.\" Man page generated from reStructuredText.
|
||||
.
|
||||
.
|
||||
.nr rst2man-indent-level 0
|
||||
.
|
||||
.de1 rstReportMargin
|
||||
\\$1 \\n[an-margin]
|
||||
level \\n[rst2man-indent-level]
|
||||
level margin: \\n[rst2man-indent\\n[rst2man-indent-level]]
|
||||
-
|
||||
\\n[rst2man-indent0]
|
||||
\\n[rst2man-indent1]
|
||||
\\n[rst2man-indent2]
|
||||
..
|
||||
.de1 INDENT
|
||||
.\" .rstReportMargin pre:
|
||||
. RS \\$1
|
||||
. nr rst2man-indent\\n[rst2man-indent-level] \\n[an-margin]
|
||||
. nr rst2man-indent-level +1
|
||||
.\" .rstReportMargin post:
|
||||
..
|
||||
.de UNINDENT
|
||||
. RE
|
||||
.\" indent \\n[an-margin]
|
||||
.\" old: \\n[rst2man-indent\\n[rst2man-indent-level]]
|
||||
.nr rst2man-indent-level -1
|
||||
.\" new: \\n[rst2man-indent\\n[rst2man-indent-level]]
|
||||
.in \\n[rst2man-indent\\n[rst2man-indent-level]]u
|
||||
..
|
||||
.TH "UNBOUND-ANCHOR" "8" "@date@" "@version@" "Unbound"
|
||||
.SH NAME
|
||||
unbound-anchor \- Unbound @version@ anchor utility.
|
||||
.SH SYNOPSIS
|
||||
.sp
|
||||
\fBunbound\-anchor\fP [\fBopts\fP]
|
||||
.SH DESCRIPTION
|
||||
.sp
|
||||
\fBunbound\-anchor\fP performs setup or update of the root trust anchor for DNSSEC
|
||||
validation.
|
||||
The program fetches the trust anchor with the method from \fI\%RFC 7958\fP when
|
||||
regular \fI\%RFC 5011\fP update fails to bring it up to date.
|
||||
It can be run from the commandline, or run as part of startup scripts before
|
||||
you start the \fI\%unbound(8)\fP DNS server.
|
||||
.sp
|
||||
Note that if you want to use \fI\%RFC 5011\fP with Unbound (i.e., the
|
||||
\fI\%auto\-trust\-anchor\-file\fP option) so
|
||||
that trust anchor information is automatically tracked by Unbound during
|
||||
operation, the user that Unbound runs under (by default \(aqunbound\(aq) must have
|
||||
write permissions to the file and the directory the file lives in (for creating
|
||||
temporary files).
|
||||
In this case you would probably want to run this program as the designated
|
||||
Unbound user.
|
||||
.sp
|
||||
Suggested usage:
|
||||
.P
|
||||
.INDENT 0.0
|
||||
.INDENT 3.5
|
||||
.sp
|
||||
.nf
|
||||
# in the init scripts.
|
||||
# provide or update the root anchor (if necessary)
|
||||
unbound-anchor \-a "@UNBOUND_ROOTKEY_FILE@"
|
||||
# Please note usage of this root anchor is at your own risk
|
||||
# and under the terms of our LICENSE (see source).
|
||||
#
|
||||
# start validating resolver
|
||||
# the unbound.conf contains:
|
||||
# auto-trust-anchor-file: "@UNBOUND_ROOTKEY_FILE@"
|
||||
unbound \-c unbound.conf
|
||||
.ft C
|
||||
# in the init scripts.
|
||||
# provide or update the root anchor (if necessary)
|
||||
unbound\-anchor \-a \(dq@UNBOUND_ROOTKEY_FILE@\(dq
|
||||
|
||||
# Please note usage of this root anchor is at your own risk
|
||||
# and under the terms of our LICENSE (see source).
|
||||
#
|
||||
# start validating resolver
|
||||
# the unbound.conf contains:
|
||||
# auto\-trust\-anchor\-file: \(dq@UNBOUND_ROOTKEY_FILE@\(dq
|
||||
unbound \-c unbound.conf
|
||||
.ft P
|
||||
.fi
|
||||
.P
|
||||
This tool provides builtin default contents for the root anchor and root
|
||||
update certificate files.
|
||||
.P
|
||||
.UNINDENT
|
||||
.UNINDENT
|
||||
.sp
|
||||
This tool provides builtin default contents for the root anchor and root update
|
||||
certificate files.
|
||||
.sp
|
||||
It tests if the root anchor file works, and if not, and an update is possible,
|
||||
attempts to update the root anchor using the root update certificate.
|
||||
It performs a https fetch of root-anchors.xml and checks the results (RFC7958),
|
||||
if all checks are successful, it updates the root anchor file. Otherwise
|
||||
the root anchor file is unchanged. It performs RFC5011 tracking if the
|
||||
DNSSEC information available via the DNS makes that possible.
|
||||
.P
|
||||
It does not perform an update if the certificate is expired, if the network
|
||||
is down or other errors occur.
|
||||
.P
|
||||
It performs a https fetch of
|
||||
\fI\%root\-anchors.xml\fP
|
||||
and checks the results (\fI\%RFC 7958\fP); if all checks are successful, it updates
|
||||
the root anchor file.
|
||||
Otherwise the root anchor file is unchanged.
|
||||
It performs \fI\%RFC 5011\fP tracking if the DNSSEC information available via the
|
||||
DNS makes that possible.
|
||||
.sp
|
||||
It does not perform an update if the certificate is expired, if the network is
|
||||
down or other errors occur.
|
||||
.sp
|
||||
The available options are:
|
||||
.INDENT 0.0
|
||||
.TP
|
||||
.B \-a \fIfile
|
||||
.B \-a <file>
|
||||
The root anchor key file, that is read in and written out.
|
||||
Default is @UNBOUND_ROOTKEY_FILE@.
|
||||
If the file does not exist, or is empty, a builtin root key is written to it.
|
||||
Default is \fB@UNBOUND_ROOTKEY_FILE@\fP\&.
|
||||
If the file does not exist, or is empty, a builtin root key is written
|
||||
to it.
|
||||
.UNINDENT
|
||||
.INDENT 0.0
|
||||
.TP
|
||||
.B \-c \fIfile
|
||||
.B \-c <file>
|
||||
The root update certificate file, that is read in.
|
||||
Default is @UNBOUND_ROOTCERT_FILE@.
|
||||
Default is \fB@UNBOUND_ROOTCERT_FILE@\fP\&.
|
||||
If the file does not exist, or is empty, a builtin certificate is used.
|
||||
.UNINDENT
|
||||
.INDENT 0.0
|
||||
.TP
|
||||
.B \-l
|
||||
List the builtin root key and builtin root update certificate on stdout.
|
||||
.UNINDENT
|
||||
.INDENT 0.0
|
||||
.TP
|
||||
.B \-u \fIname
|
||||
The server name, it connects to https://name. Specify without https:// prefix.
|
||||
The default is "data.iana.org". It connects to the port specified with \-P.
|
||||
.B \-u <name>
|
||||
The server name, it connects to \fBhttps://name\fP\&.
|
||||
Specify without \fBhttps://\fP prefix.
|
||||
The default is \fB\(dqdata.iana.org\(dq\fP\&.
|
||||
It connects to the port specified with \fI\%\-P\fP\&.
|
||||
You can pass an IPv4 address or IPv6 address (no brackets) if you want.
|
||||
.UNINDENT
|
||||
.INDENT 0.0
|
||||
.TP
|
||||
.B \-S
|
||||
Do not use SNI for the HTTPS connection. Default is to use SNI.
|
||||
Do not use SNI for the HTTPS connection.
|
||||
Default is to use SNI.
|
||||
.UNINDENT
|
||||
.INDENT 0.0
|
||||
.TP
|
||||
.B \-b \fIaddress
|
||||
The source address to bind to for domain resolution and contacting the server
|
||||
on https. May be either an IPv4 address or IPv6 address (no brackets).
|
||||
.B \-b <address>
|
||||
The source address to bind to for domain resolution and contacting the
|
||||
server on https.
|
||||
May be either an IPv4 address or IPv6 address (no brackets).
|
||||
.UNINDENT
|
||||
.INDENT 0.0
|
||||
.TP
|
||||
.B \-x \fIpath
|
||||
The pathname to the root\-anchors.xml file on the server. (forms URL with \-u).
|
||||
The default is /root\-anchors/root\-anchors.xml.
|
||||
.B \-x <path>
|
||||
The pathname to the root\-anchors.xml file on the server.
|
||||
(forms URL with \fI\%\-u\fP).
|
||||
The default is \fB/root\-anchors/root\-anchors.xml\fP\&.
|
||||
.UNINDENT
|
||||
.INDENT 0.0
|
||||
.TP
|
||||
.B \-s \fIpath
|
||||
The pathname to the root\-anchors.p7s file on the server. (forms URL with \-u).
|
||||
The default is /root\-anchors/root\-anchors.p7s. This file has to be a PKCS7
|
||||
signature over the xml file, using the pem file (\-c) as trust anchor.
|
||||
.B \-s <path>
|
||||
The pathname to the root\-anchors.p7s file on the server.
|
||||
(forms URL with \fI\%\-u\fP).
|
||||
The default is \fB/root\-anchors/root\-anchors.p7s\fP\&.
|
||||
This file has to be a PKCS7 signature over the xml file, using the pem
|
||||
file (\fI\%\-c\fP) as trust anchor.
|
||||
.UNINDENT
|
||||
.INDENT 0.0
|
||||
.TP
|
||||
.B \-n \fIname
|
||||
The emailAddress for the Subject of the signer's certificate from the p7s
|
||||
signature file. Only signatures from this name are allowed. default is
|
||||
dnssec@iana.org. If you pass "" then the emailAddress is not checked.
|
||||
.B \-n <name>
|
||||
The emailAddress for the Subject of the signer\(aqs certificate from the
|
||||
p7s signature file.
|
||||
Only signatures from this name are allowed.
|
||||
The default is \fBdnssec@iana.org\fP\&.
|
||||
If you pass \fB\(dq\(dq\fP then the emailAddress is not checked.
|
||||
.UNINDENT
|
||||
.INDENT 0.0
|
||||
.TP
|
||||
.B \-4
|
||||
Use IPv4 for domain resolution and contacting the server on https. Default is
|
||||
to use IPv4 and IPv6 where appropriate.
|
||||
Use IPv4 for domain resolution and contacting the server on
|
||||
https.
|
||||
Default is to use IPv4 and IPv6 where appropriate.
|
||||
.UNINDENT
|
||||
.INDENT 0.0
|
||||
.TP
|
||||
.B \-6
|
||||
Use IPv6 for domain resolution and contacting the server on https. Default is
|
||||
to use IPv4 and IPv6 where appropriate.
|
||||
Use IPv6 for domain resolution and contacting the server on https.
|
||||
Default is to use IPv4 and IPv6 where appropriate.
|
||||
.UNINDENT
|
||||
.INDENT 0.0
|
||||
.TP
|
||||
.B \-f \fIresolv.conf
|
||||
Use the given resolv.conf file. Not enabled by default, but you could try to
|
||||
pass /etc/resolv.conf on some systems. It contains the IP addresses of the
|
||||
recursive nameservers to use. However, since this tool could be used to
|
||||
bootstrap that very recursive nameserver, it would not be useful (since
|
||||
that server is not up yet, since we are bootstrapping it). It could be
|
||||
useful in a situation where you know an upstream cache is deployed (and
|
||||
running) and in captive portal situations.
|
||||
.B \-f <resolv.conf>
|
||||
Use the given resolv.conf file.
|
||||
Not enabled by default, but you could try to pass
|
||||
\fB/etc/resolv.conf\fP on some systems.
|
||||
It contains the IP addresses of the recursive nameservers to use.
|
||||
However, since this tool could be used to bootstrap that very recursive
|
||||
nameserver, it would not be useful (since that server is not up yet,
|
||||
since we are bootstrapping it).
|
||||
It could be useful in a situation where you know an upstream cache is
|
||||
deployed (and running) and in captive portal situations.
|
||||
.UNINDENT
|
||||
.INDENT 0.0
|
||||
.TP
|
||||
.B \-r \fIroot.hints
|
||||
Use the given root.hints file (same syntax as the BIND and Unbound root hints
|
||||
file) to bootstrap domain resolution. By default a list of builtin root
|
||||
hints is used. Unbound\-anchor goes to the network itself for these roots,
|
||||
to resolve the server (\-u option) and to check the root DNSKEY records.
|
||||
.B \-r <root.hints>
|
||||
Use the given root.hints file (same syntax as the BIND and Unbound root
|
||||
hints file) to bootstrap domain resolution.
|
||||
By default a list of builtin root hints is used.
|
||||
unbound\-anchor goes to the network itself for these roots, to resolve
|
||||
the server (\fI\%\-u\fP option) and to check the root DNSKEY records.
|
||||
It does so, because the tool when used for bootstrapping the recursive
|
||||
resolver, cannot use that recursive resolver itself because it is bootstrapping
|
||||
that server.
|
||||
resolver, cannot use that recursive resolver itself because it is
|
||||
bootstrapping that server.
|
||||
.UNINDENT
|
||||
.INDENT 0.0
|
||||
.TP
|
||||
.B \-R
|
||||
Allow fallback from \-f resolv.conf file to direct root servers query.
|
||||
It allows you to prefer local resolvers, but fallback automatically
|
||||
to direct root query if they do not respond or do not support DNSSEC.
|
||||
Allow fallback from \fI\%\-f\fP \fB<resolv.conf>\fP file to direct root
|
||||
servers query.
|
||||
It allows you to prefer local resolvers, but fallback automatically to
|
||||
direct root query if they do not respond or do not support DNSSEC.
|
||||
.UNINDENT
|
||||
.INDENT 0.0
|
||||
.TP
|
||||
.B \-v
|
||||
More verbose. Once prints informational messages, multiple times may enable
|
||||
large debug amounts (such as full certificates or byte\-dumps of downloaded
|
||||
files). By default it prints almost nothing. It also prints nothing on
|
||||
errors by default; in that case the original root anchor file is simply
|
||||
left undisturbed, so that a recursive server can start right after it.
|
||||
More verbose.
|
||||
Once prints informational messages, multiple times may enable large
|
||||
debug amounts (such as full certificates or byte\-dumps of downloaded
|
||||
files).
|
||||
By default it prints almost nothing.
|
||||
It also prints nothing on errors by default; in that case the original
|
||||
root anchor file is simply left undisturbed, so that a recursive server
|
||||
can start right after it.
|
||||
.UNINDENT
|
||||
.INDENT 0.0
|
||||
.TP
|
||||
.B \-C \fIunbound.conf
|
||||
Debug option to read unbound.conf into the resolver process used.
|
||||
.B \-C <unbound.conf>
|
||||
Debug option to read \fB<unbound.conf>\fP into the resolver process
|
||||
used.
|
||||
.UNINDENT
|
||||
.INDENT 0.0
|
||||
.TP
|
||||
.B \-P \fIport
|
||||
Set the port number to use for the https connection. The default is 443.
|
||||
.B \-P <port>
|
||||
Set the port number to use for the https connection.
|
||||
The default is 443.
|
||||
.UNINDENT
|
||||
.INDENT 0.0
|
||||
.TP
|
||||
.B \-F
|
||||
Debug option to force update of the root anchor through downloading the xml
|
||||
file and verifying it with the certificate. By default it first tries to
|
||||
update by contacting the DNS, which uses much less bandwidth, is much
|
||||
faster (200 msec not 2 sec), and is nicer to the deployed infrastructure.
|
||||
With this option, it still attempts to do so (and may verbosely tell you),
|
||||
but then ignores the result and goes on to use the xml fallback method.
|
||||
Debug option to force update of the root anchor through downloading the
|
||||
xml file and verifying it with the certificate.
|
||||
By default it first tries to update by contacting the DNS, which uses
|
||||
much less bandwidth, is much faster (200 msec not 2 sec), and is nicer
|
||||
to the deployed infrastructure.
|
||||
With this option, it still attempts to do so (and may verbosely tell
|
||||
you), but then ignores the result and goes on to use the xml fallback
|
||||
method.
|
||||
.UNINDENT
|
||||
.INDENT 0.0
|
||||
.TP
|
||||
.B \-h
|
||||
Show the version and commandline option help.
|
||||
.SH "EXIT CODE"
|
||||
.UNINDENT
|
||||
.SH EXIT CODE
|
||||
.sp
|
||||
This tool exits with value 1 if the root anchor was updated using the
|
||||
certificate or if the builtin root-anchor was used. It exits with code
|
||||
0 if no update was necessary, if the update was possible with RFC5011
|
||||
tracking, or if an error occurred.
|
||||
.P
|
||||
certificate or if the builtin root\-anchor was used.
|
||||
It exits with code 0 if no update was necessary, if the update was possible
|
||||
with \fI\%RFC 5011\fP tracking, or if an error occurred.
|
||||
.sp
|
||||
You can check the exit value in this manner:
|
||||
.INDENT 0.0
|
||||
.INDENT 3.5
|
||||
.sp
|
||||
.nf
|
||||
unbound-anchor \-a "root.key" || logger "Please check root.key"
|
||||
.ft C
|
||||
unbound\-anchor \-a \(dqroot.key\(dq || logger \(dqPlease check root.key\(dq
|
||||
.ft P
|
||||
.fi
|
||||
.UNINDENT
|
||||
.UNINDENT
|
||||
.sp
|
||||
Or something more suitable for your operational environment.
|
||||
.SH "TRUST"
|
||||
The root keys and update certificate included in this tool
|
||||
are provided for convenience and under the terms of our
|
||||
license (see the LICENSE file in the source distribution or
|
||||
https://github.com/NLnetLabs/unbound/blob/master/LICENSE) and might be stale or
|
||||
not suitable to your purpose.
|
||||
.P
|
||||
By running "unbound\-anchor \-l" the keys and certificate that are
|
||||
.SH TRUST
|
||||
.sp
|
||||
The root keys and update certificate included in this tool are provided for
|
||||
convenience and under the terms of our license (see the LICENSE file in the
|
||||
source distribution or \fI\%https://github.com/NLnetLabs/unbound/blob/master/LICENSE\fP
|
||||
and might be stale or not suitable to your purpose.
|
||||
.sp
|
||||
By running \fI\%unbound\-anchor \-l\fP the keys and certificate that are
|
||||
configured in the code are printed for your convenience.
|
||||
.P
|
||||
The build\-in configuration can be overridden by providing a root\-cert
|
||||
file and a rootkey file.
|
||||
.SH "FILES"
|
||||
.sp
|
||||
The built\-in configuration can be overridden by providing a root\-cert file and
|
||||
a rootkey file.
|
||||
.SH FILES
|
||||
.INDENT 0.0
|
||||
.TP
|
||||
.I @UNBOUND_ROOTKEY_FILE@
|
||||
The root anchor file, updated with 5011 tracking, and read and written to.
|
||||
.B @UNBOUND_ROOTKEY_FILE@
|
||||
The root anchor file, updated with 5011 tracking, and read and written
|
||||
to.
|
||||
The file is created if it does not exist.
|
||||
.TP
|
||||
.I @UNBOUND_ROOTCERT_FILE@
|
||||
The trusted self\-signed certificate that is used to verify the downloaded
|
||||
DNSSEC root trust anchor. You can update it by fetching it from
|
||||
https://data.iana.org/root\-anchors/icannbundle.pem (and validate it).
|
||||
.B @UNBOUND_ROOTCERT_FILE@
|
||||
The trusted self\-signed certificate that is used to verify the
|
||||
downloaded DNSSEC root trust anchor.
|
||||
You can update it by fetching it from
|
||||
\fI\%https://data.iana.org/root\-anchors/icannbundle.pem\fP (and validate it).
|
||||
If the file does not exist or is empty, a builtin version is used.
|
||||
.TP
|
||||
.I https://data.iana.org/root\-anchors/root\-anchors.xml
|
||||
.B \fI\%https://data.iana.org/root\-anchors/root\-anchors.xml\fP
|
||||
Source for the root key information.
|
||||
.TP
|
||||
.I https://data.iana.org/root\-anchors/root\-anchors.p7s
|
||||
.B \fI\%https://data.iana.org/root\-anchors/root\-anchors.p7s\fP
|
||||
Signature on the root key information.
|
||||
.SH "SEE ALSO"
|
||||
\fIunbound.conf\fR(5),
|
||||
\fIunbound\fR(8).
|
||||
.UNINDENT
|
||||
.SH SEE ALSO
|
||||
.sp
|
||||
\fI\%unbound.conf(5)\fP,
|
||||
\fI\%unbound(8)\fP\&.
|
||||
.SH AUTHOR
|
||||
Unbound developers are mentioned in the CREDITS file in the distribution.
|
||||
.SH COPYRIGHT
|
||||
1999-2026, NLnet Labs
|
||||
.\" Generated by docutils manpage writer.
|
||||
.
|
||||
|
||||
@@ -0,0 +1,290 @@
|
||||
..
|
||||
WHEN EDITING MAKE SURE EACH SENTENCE STARTS ON A NEW LINE
|
||||
|
||||
..
|
||||
IT HELPS RENDERERS TO DO THE RIGHT THING WRT SPACE
|
||||
|
||||
..
|
||||
IT HELPS PEOPLE DIFFING THE CHANGES
|
||||
|
||||
..
|
||||
WHEN EDITING MAKE SURE EACH SENTENCE STARTS ON A NEW LINE
|
||||
|
||||
..
|
||||
IT HELPS RENDERERS TO DO THE RIGHT THING WRT SPACE
|
||||
|
||||
..
|
||||
IT HELPS PEOPLE DIFFING THE CHANGES
|
||||
|
||||
..
|
||||
WHEN EDITING MAKE SURE EACH SENTENCE STARTS ON A NEW LINE
|
||||
|
||||
..
|
||||
IT HELPS RENDERERS TO DO THE RIGHT THING WRT SPACE
|
||||
|
||||
..
|
||||
IT HELPS PEOPLE DIFFING THE CHANGES
|
||||
|
||||
..
|
||||
WHEN EDITING MAKE SURE EACH SENTENCE STARTS ON A NEW LINE
|
||||
|
||||
..
|
||||
IT HELPS RENDERERS TO DO THE RIGHT THING WRT SPACE
|
||||
|
||||
..
|
||||
IT HELPS PEOPLE DIFFING THE CHANGES
|
||||
|
||||
.. program:: unbound-anchor
|
||||
|
||||
unbound-anchor(8)
|
||||
=================
|
||||
|
||||
Synopsis
|
||||
--------
|
||||
|
||||
**unbound-anchor** [``opts``]
|
||||
|
||||
Description
|
||||
-----------
|
||||
|
||||
``unbound-anchor`` performs setup or update of the root trust anchor for DNSSEC
|
||||
validation.
|
||||
The program fetches the trust anchor with the method from :rfc:`7958` when
|
||||
regular :rfc:`5011` update fails to bring it up to date.
|
||||
It can be run from the commandline, or run as part of startup scripts before
|
||||
you start the :doc:`unbound(8)</manpages/unbound>` DNS server.
|
||||
|
||||
Note that if you want to use :rfc:`5011` with Unbound (i.e., the
|
||||
:ref:`auto-trust-anchor-file<unbound.conf.auto-trust-anchor-file>` option) so
|
||||
that trust anchor information is automatically tracked by Unbound during
|
||||
operation, the user that Unbound runs under (by default 'unbound') must have
|
||||
write permissions to the file and the directory the file lives in (for creating
|
||||
temporary files).
|
||||
In this case you would probably want to run this program as the designated
|
||||
Unbound user.
|
||||
|
||||
Suggested usage:
|
||||
|
||||
.. code-block:: text
|
||||
|
||||
# in the init scripts.
|
||||
# provide or update the root anchor (if necessary)
|
||||
unbound-anchor -a "@UNBOUND_ROOTKEY_FILE@"
|
||||
|
||||
# Please note usage of this root anchor is at your own risk
|
||||
# and under the terms of our LICENSE (see source).
|
||||
#
|
||||
# start validating resolver
|
||||
# the unbound.conf contains:
|
||||
# auto-trust-anchor-file: "@UNBOUND_ROOTKEY_FILE@"
|
||||
unbound -c unbound.conf
|
||||
|
||||
This tool provides builtin default contents for the root anchor and root update
|
||||
certificate files.
|
||||
|
||||
It tests if the root anchor file works, and if not, and an update is possible,
|
||||
attempts to update the root anchor using the root update certificate.
|
||||
It performs a https fetch of
|
||||
`root-anchors.xml <http://data.iana.org/root-anchors/root-anchors.xml>`__
|
||||
and checks the results (:rfc:`7958`); if all checks are successful, it updates
|
||||
the root anchor file.
|
||||
Otherwise the root anchor file is unchanged.
|
||||
It performs :rfc:`5011` tracking if the DNSSEC information available via the
|
||||
DNS makes that possible.
|
||||
|
||||
It does not perform an update if the certificate is expired, if the network is
|
||||
down or other errors occur.
|
||||
|
||||
The available options are:
|
||||
|
||||
.. option:: -a <file>
|
||||
|
||||
The root anchor key file, that is read in and written out.
|
||||
Default is :file:`@UNBOUND_ROOTKEY_FILE@`.
|
||||
If the file does not exist, or is empty, a builtin root key is written
|
||||
to it.
|
||||
|
||||
.. option:: -c <file>
|
||||
|
||||
The root update certificate file, that is read in.
|
||||
Default is :file:`@UNBOUND_ROOTCERT_FILE@`.
|
||||
If the file does not exist, or is empty, a builtin certificate is used.
|
||||
|
||||
.. option:: -l
|
||||
|
||||
List the builtin root key and builtin root update certificate on stdout.
|
||||
|
||||
.. option:: -u <name>
|
||||
|
||||
The server name, it connects to ``https://name``.
|
||||
Specify without ``https://`` prefix.
|
||||
The default is ``"data.iana.org"``.
|
||||
It connects to the port specified with :option:`-P`.
|
||||
You can pass an IPv4 address or IPv6 address (no brackets) if you want.
|
||||
|
||||
.. option:: -S
|
||||
|
||||
Do not use SNI for the HTTPS connection.
|
||||
Default is to use SNI.
|
||||
|
||||
.. option:: -b <address>
|
||||
|
||||
The source address to bind to for domain resolution and contacting the
|
||||
server on https.
|
||||
May be either an IPv4 address or IPv6 address (no brackets).
|
||||
|
||||
.. option:: -x <path>
|
||||
|
||||
The pathname to the root-anchors.xml file on the server.
|
||||
(forms URL with :option:`-u`).
|
||||
The default is :file:`/root-anchors/root-anchors.xml`.
|
||||
|
||||
.. option:: -s <path>
|
||||
|
||||
The pathname to the root-anchors.p7s file on the server.
|
||||
(forms URL with :option:`-u`).
|
||||
The default is :file:`/root-anchors/root-anchors.p7s`.
|
||||
This file has to be a PKCS7 signature over the xml file, using the pem
|
||||
file (:option:`-c`) as trust anchor.
|
||||
|
||||
.. option:: -n <name>
|
||||
|
||||
The emailAddress for the Subject of the signer's certificate from the
|
||||
p7s signature file.
|
||||
Only signatures from this name are allowed.
|
||||
The default is ``dnssec@iana.org``.
|
||||
If you pass ``""`` then the emailAddress is not checked.
|
||||
|
||||
.. option:: -4
|
||||
|
||||
Use IPv4 for domain resolution and contacting the server on
|
||||
https.
|
||||
Default is to use IPv4 and IPv6 where appropriate.
|
||||
|
||||
.. option:: -6
|
||||
|
||||
Use IPv6 for domain resolution and contacting the server on https.
|
||||
Default is to use IPv4 and IPv6 where appropriate.
|
||||
|
||||
.. option:: -f <resolv.conf>
|
||||
|
||||
Use the given resolv.conf file.
|
||||
Not enabled by default, but you could try to pass
|
||||
:file:`/etc/resolv.conf` on some systems.
|
||||
It contains the IP addresses of the recursive nameservers to use.
|
||||
However, since this tool could be used to bootstrap that very recursive
|
||||
nameserver, it would not be useful (since that server is not up yet,
|
||||
since we are bootstrapping it).
|
||||
It could be useful in a situation where you know an upstream cache is
|
||||
deployed (and running) and in captive portal situations.
|
||||
|
||||
.. option:: -r <root.hints>
|
||||
|
||||
Use the given root.hints file (same syntax as the BIND and Unbound root
|
||||
hints file) to bootstrap domain resolution.
|
||||
By default a list of builtin root hints is used.
|
||||
unbound-anchor goes to the network itself for these roots, to resolve
|
||||
the server (:option:`-u` option) and to check the root DNSKEY records.
|
||||
It does so, because the tool when used for bootstrapping the recursive
|
||||
resolver, cannot use that recursive resolver itself because it is
|
||||
bootstrapping that server.
|
||||
|
||||
.. option:: -R
|
||||
|
||||
Allow fallback from :option:`-f` ``<resolv.conf>`` file to direct root
|
||||
servers query.
|
||||
It allows you to prefer local resolvers, but fallback automatically to
|
||||
direct root query if they do not respond or do not support DNSSEC.
|
||||
|
||||
.. option:: -v
|
||||
|
||||
More verbose.
|
||||
Once prints informational messages, multiple times may enable large
|
||||
debug amounts (such as full certificates or byte-dumps of downloaded
|
||||
files).
|
||||
By default it prints almost nothing.
|
||||
It also prints nothing on errors by default; in that case the original
|
||||
root anchor file is simply left undisturbed, so that a recursive server
|
||||
can start right after it.
|
||||
|
||||
.. option:: -C <unbound.conf>
|
||||
|
||||
Debug option to read :file:`<unbound.conf>` into the resolver process
|
||||
used.
|
||||
|
||||
.. option:: -P <port>
|
||||
|
||||
Set the port number to use for the https connection.
|
||||
The default is 443.
|
||||
|
||||
.. option:: -F
|
||||
|
||||
Debug option to force update of the root anchor through downloading the
|
||||
xml file and verifying it with the certificate.
|
||||
By default it first tries to update by contacting the DNS, which uses
|
||||
much less bandwidth, is much faster (200 msec not 2 sec), and is nicer
|
||||
to the deployed infrastructure.
|
||||
With this option, it still attempts to do so (and may verbosely tell
|
||||
you), but then ignores the result and goes on to use the xml fallback
|
||||
method.
|
||||
|
||||
.. option:: -h
|
||||
|
||||
Show the version and commandline option help.
|
||||
|
||||
Exit Code
|
||||
---------
|
||||
|
||||
This tool exits with value 1 if the root anchor was updated using the
|
||||
certificate or if the builtin root-anchor was used.
|
||||
It exits with code 0 if no update was necessary, if the update was possible
|
||||
with :rfc:`5011` tracking, or if an error occurred.
|
||||
|
||||
You can check the exit value in this manner:
|
||||
|
||||
.. code-block:: text
|
||||
|
||||
unbound-anchor -a "root.key" || logger "Please check root.key"
|
||||
|
||||
Or something more suitable for your operational environment.
|
||||
|
||||
Trust
|
||||
-----
|
||||
|
||||
The root keys and update certificate included in this tool are provided for
|
||||
convenience and under the terms of our license (see the LICENSE file in the
|
||||
source distribution or https://github.com/NLnetLabs/unbound/blob/master/LICENSE
|
||||
and might be stale or not suitable to your purpose.
|
||||
|
||||
By running :option:`unbound-anchor -l` the keys and certificate that are
|
||||
configured in the code are printed for your convenience.
|
||||
|
||||
The built-in configuration can be overridden by providing a root-cert file and
|
||||
a rootkey file.
|
||||
|
||||
Files
|
||||
-----
|
||||
|
||||
@UNBOUND_ROOTKEY_FILE@
|
||||
The root anchor file, updated with 5011 tracking, and read and written
|
||||
to.
|
||||
The file is created if it does not exist.
|
||||
|
||||
@UNBOUND_ROOTCERT_FILE@
|
||||
The trusted self-signed certificate that is used to verify the
|
||||
downloaded DNSSEC root trust anchor.
|
||||
You can update it by fetching it from
|
||||
https://data.iana.org/root-anchors/icannbundle.pem (and validate it).
|
||||
If the file does not exist or is empty, a builtin version is used.
|
||||
|
||||
https://data.iana.org/root-anchors/root-anchors.xml
|
||||
Source for the root key information.
|
||||
|
||||
https://data.iana.org/root-anchors/root-anchors.p7s
|
||||
Signature on the root key information.
|
||||
|
||||
See Also
|
||||
--------
|
||||
|
||||
:doc:`unbound.conf(5)</manpages/unbound.conf>`,
|
||||
:doc:`unbound(8)</manpages/unbound>`.
|
||||
+79
-42
@@ -1,56 +1,93 @@
|
||||
.TH "unbound-checkconf" "8" "@date@" "NLnet Labs" "unbound @version@"
|
||||
.\"
|
||||
.\" unbound-checkconf.8 -- unbound configuration checker manual
|
||||
.\"
|
||||
.\" Copyright (c) 2007, NLnet Labs. All rights reserved.
|
||||
.\"
|
||||
.\" See LICENSE for the license.
|
||||
.\"
|
||||
.\"
|
||||
.SH "NAME"
|
||||
unbound\-checkconf
|
||||
\- Check Unbound configuration file for errors.
|
||||
.SH "SYNOPSIS"
|
||||
.B unbound\-checkconf
|
||||
.RB [ \-h ]
|
||||
.RB [ \-f ]
|
||||
.RB [ \-q ]
|
||||
.RB [ \-o
|
||||
.IR option ]
|
||||
.RI [ cfgfile ]
|
||||
.SH "DESCRIPTION"
|
||||
.B Unbound\-checkconf
|
||||
checks the configuration file for the
|
||||
\fIunbound\fR(8)
|
||||
DNS resolver for syntax and other errors.
|
||||
.\" Man page generated from reStructuredText.
|
||||
.
|
||||
.
|
||||
.nr rst2man-indent-level 0
|
||||
.
|
||||
.de1 rstReportMargin
|
||||
\\$1 \\n[an-margin]
|
||||
level \\n[rst2man-indent-level]
|
||||
level margin: \\n[rst2man-indent\\n[rst2man-indent-level]]
|
||||
-
|
||||
\\n[rst2man-indent0]
|
||||
\\n[rst2man-indent1]
|
||||
\\n[rst2man-indent2]
|
||||
..
|
||||
.de1 INDENT
|
||||
.\" .rstReportMargin pre:
|
||||
. RS \\$1
|
||||
. nr rst2man-indent\\n[rst2man-indent-level] \\n[an-margin]
|
||||
. nr rst2man-indent-level +1
|
||||
.\" .rstReportMargin post:
|
||||
..
|
||||
.de UNINDENT
|
||||
. RE
|
||||
.\" indent \\n[an-margin]
|
||||
.\" old: \\n[rst2man-indent\\n[rst2man-indent-level]]
|
||||
.nr rst2man-indent-level -1
|
||||
.\" new: \\n[rst2man-indent\\n[rst2man-indent-level]]
|
||||
.in \\n[rst2man-indent\\n[rst2man-indent-level]]u
|
||||
..
|
||||
.TH "UNBOUND-CHECKCONF" "8" "@date@" "@version@" "Unbound"
|
||||
.SH NAME
|
||||
unbound-checkconf \- Check Unbound @version@ configuration file for errors.
|
||||
.SH SYNOPSIS
|
||||
.sp
|
||||
\fBunbound\-checkconf\fP [\fB\-hf\fP] [\fB\-o option\fP] [cfgfile]
|
||||
.SH DESCRIPTION
|
||||
.sp
|
||||
\fBunbound\-checkconf\fP checks the configuration file for the
|
||||
\fI\%unbound(8)\fP DNS resolver for syntax and other errors.
|
||||
The config file syntax is described in
|
||||
\fIunbound.conf\fR(5).
|
||||
.P
|
||||
\fI\%unbound.conf(5)\fP\&.
|
||||
.sp
|
||||
The available options are:
|
||||
.INDENT 0.0
|
||||
.TP
|
||||
.B \-h
|
||||
Show the version and commandline option help.
|
||||
.UNINDENT
|
||||
.INDENT 0.0
|
||||
.TP
|
||||
.B \-f
|
||||
Print full pathname, with chroot applied to it. Use with the \-o option.
|
||||
.TP
|
||||
.B \-o\fI 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.
|
||||
Print full pathname, with chroot applied to it.
|
||||
Use with the \fI\%\-o\fP option.
|
||||
.UNINDENT
|
||||
.INDENT 0.0
|
||||
.TP
|
||||
.B \-q
|
||||
Make the operation quiet, suppress output on success.
|
||||
.UNINDENT
|
||||
.INDENT 0.0
|
||||
.TP
|
||||
.I cfgfile
|
||||
The config file to read with settings for Unbound. It is checked.
|
||||
.B \-o <option>
|
||||
If given, after checking the config file the value of this option is
|
||||
printed to stdout.
|
||||
For \fB\(dq\(dq\fP (disabled) options an empty line is printed.
|
||||
.UNINDENT
|
||||
.INDENT 0.0
|
||||
.TP
|
||||
.B cfgfile
|
||||
The config file to read with settings for Unbound.
|
||||
It is checked.
|
||||
If omitted, the config file at the default location is checked.
|
||||
.SH "EXIT CODE"
|
||||
The unbound\-checkconf program exits with status code 1 on error,
|
||||
0 for a correct config file.
|
||||
.SH "FILES"
|
||||
.UNINDENT
|
||||
.SH EXIT CODE
|
||||
.sp
|
||||
The \fBunbound\-checkconf\fP program exits with status code 1 on error, 0 for a
|
||||
correct config file.
|
||||
.SH FILES
|
||||
.INDENT 0.0
|
||||
.TP
|
||||
.I @ub_conf_file@
|
||||
.B @ub_conf_file@
|
||||
Unbound configuration file.
|
||||
.SH "SEE ALSO"
|
||||
\fIunbound.conf\fR(5),
|
||||
\fIunbound\fR(8).
|
||||
.UNINDENT
|
||||
.SH SEE ALSO
|
||||
.sp
|
||||
\fI\%unbound.conf(5)\fP,
|
||||
\fI\%unbound(8)\fP\&.
|
||||
.SH AUTHOR
|
||||
Unbound developers are mentioned in the CREDITS file in the distribution.
|
||||
.SH COPYRIGHT
|
||||
1999-2026, NLnet Labs
|
||||
.\" Generated by docutils manpage writer.
|
||||
.
|
||||
|
||||
@@ -0,0 +1,98 @@
|
||||
..
|
||||
WHEN EDITING MAKE SURE EACH SENTENCE STARTS ON A NEW LINE
|
||||
|
||||
..
|
||||
IT HELPS RENDERERS TO DO THE RIGHT THING WRT SPACE
|
||||
|
||||
..
|
||||
IT HELPS PEOPLE DIFFING THE CHANGES
|
||||
|
||||
..
|
||||
WHEN EDITING MAKE SURE EACH SENTENCE STARTS ON A NEW LINE
|
||||
|
||||
..
|
||||
IT HELPS RENDERERS TO DO THE RIGHT THING WRT SPACE
|
||||
|
||||
..
|
||||
IT HELPS PEOPLE DIFFING THE CHANGES
|
||||
|
||||
..
|
||||
WHEN EDITING MAKE SURE EACH SENTENCE STARTS ON A NEW LINE
|
||||
|
||||
..
|
||||
IT HELPS RENDERERS TO DO THE RIGHT THING WRT SPACE
|
||||
|
||||
..
|
||||
IT HELPS PEOPLE DIFFING THE CHANGES
|
||||
|
||||
..
|
||||
WHEN EDITING MAKE SURE EACH SENTENCE STARTS ON A NEW LINE
|
||||
|
||||
..
|
||||
IT HELPS RENDERERS TO DO THE RIGHT THING WRT SPACE
|
||||
|
||||
..
|
||||
IT HELPS PEOPLE DIFFING THE CHANGES
|
||||
|
||||
.. program:: unbound-checkconf
|
||||
|
||||
unbound-checkconf(8)
|
||||
====================
|
||||
|
||||
Synopsis
|
||||
--------
|
||||
|
||||
**unbound-checkconf** [``-hf``] [``-o option``] [cfgfile]
|
||||
|
||||
Description
|
||||
-----------
|
||||
|
||||
``unbound-checkconf`` checks the configuration file for the
|
||||
:doc:`unbound(8)</manpages/unbound>` DNS resolver for syntax and other errors.
|
||||
The config file syntax is described in
|
||||
:doc:`unbound.conf(5)</manpages/unbound.conf>`.
|
||||
|
||||
The available options are:
|
||||
|
||||
.. option:: -h
|
||||
|
||||
Show the version and commandline option help.
|
||||
|
||||
.. option:: -f
|
||||
|
||||
Print full pathname, with chroot applied to it.
|
||||
Use with the :option:`-o` option.
|
||||
|
||||
.. option:: -q
|
||||
|
||||
Make the operation quiet, suppress output on success.
|
||||
|
||||
.. option:: -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.
|
||||
|
||||
.. option:: cfgfile
|
||||
|
||||
The config file to read with settings for Unbound.
|
||||
It is checked.
|
||||
If omitted, the config file at the default location is checked.
|
||||
|
||||
Exit Code
|
||||
---------
|
||||
|
||||
The ``unbound-checkconf`` program exits with status code 1 on error, 0 for a
|
||||
correct config file.
|
||||
|
||||
Files
|
||||
-----
|
||||
|
||||
@ub_conf_file@
|
||||
Unbound configuration file.
|
||||
|
||||
See Also
|
||||
--------
|
||||
|
||||
:doc:`unbound.conf(5)</manpages/unbound.conf>`,
|
||||
:doc:`unbound(8)</manpages/unbound>`.
|
||||
+1244
-637
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
+157
-85
@@ -1,118 +1,190 @@
|
||||
.TH "unbound\-host" "1" "@date@" "NLnet Labs" "unbound @version@"
|
||||
.\"
|
||||
.\" unbound-host.1 -- unbound DNS lookup utility
|
||||
.\"
|
||||
.\" Copyright (c) 2007, NLnet Labs. All rights reserved.
|
||||
.\"
|
||||
.\" See LICENSE for the license.
|
||||
.\"
|
||||
.\"
|
||||
.SH "NAME"
|
||||
.B unbound\-host
|
||||
\- unbound DNS lookup utility
|
||||
.SH "SYNOPSIS"
|
||||
.B unbound\-host
|
||||
.RB [ \-C
|
||||
.IR configfile ]
|
||||
.RB [ \-vdhr46D ]
|
||||
.RB [ \-c
|
||||
.IR class ]
|
||||
.RB [ \-t
|
||||
.IR type ]
|
||||
.RB [ \-y
|
||||
.IR key ]
|
||||
.RB [ \-f
|
||||
.IR keyfile ]
|
||||
.RB [ \-F
|
||||
.IR namedkeyfile ]
|
||||
.I hostname
|
||||
.SH "DESCRIPTION"
|
||||
.B Unbound\-host
|
||||
uses the Unbound validating resolver to query for the hostname and display
|
||||
results. With the \fB\-v\fR option it displays validation
|
||||
status: secure, insecure, bogus (security failure).
|
||||
.P
|
||||
By default it reads no configuration file whatsoever. It attempts to reach
|
||||
the internet root servers. With \fB\-C\fR an Unbound config file and with
|
||||
\fB\-r\fR resolv.conf can be read.
|
||||
.P
|
||||
.\" Man page generated from reStructuredText.
|
||||
.
|
||||
.
|
||||
.nr rst2man-indent-level 0
|
||||
.
|
||||
.de1 rstReportMargin
|
||||
\\$1 \\n[an-margin]
|
||||
level \\n[rst2man-indent-level]
|
||||
level margin: \\n[rst2man-indent\\n[rst2man-indent-level]]
|
||||
-
|
||||
\\n[rst2man-indent0]
|
||||
\\n[rst2man-indent1]
|
||||
\\n[rst2man-indent2]
|
||||
..
|
||||
.de1 INDENT
|
||||
.\" .rstReportMargin pre:
|
||||
. RS \\$1
|
||||
. nr rst2man-indent\\n[rst2man-indent-level] \\n[an-margin]
|
||||
. nr rst2man-indent-level +1
|
||||
.\" .rstReportMargin post:
|
||||
..
|
||||
.de UNINDENT
|
||||
. RE
|
||||
.\" indent \\n[an-margin]
|
||||
.\" old: \\n[rst2man-indent\\n[rst2man-indent-level]]
|
||||
.nr rst2man-indent-level -1
|
||||
.\" new: \\n[rst2man-indent\\n[rst2man-indent-level]]
|
||||
.in \\n[rst2man-indent\\n[rst2man-indent-level]]u
|
||||
..
|
||||
.TH "UNBOUND-HOST" "1" "@date@" "@version@" "Unbound"
|
||||
.SH NAME
|
||||
unbound-host \- Unbound @version@ DNS lookup utility.
|
||||
.SH SYNOPSIS
|
||||
.sp
|
||||
\fBunbound\-host\fP [\fB\-C configfile\fP] [\fB\-vdhr46D\fP] [\fB\-c class\fP]
|
||||
[\fB\-t type\fP] [\fB\-y key\fP] [\fB\-f keyfile\fP] [\fB\-F namedkeyfile\fP] hostname
|
||||
.SH DESCRIPTION
|
||||
.sp
|
||||
\fBunbound\-host\fP uses the Unbound validating resolver to query for the hostname
|
||||
and display results.
|
||||
With the \fI\%\-v\fP option it displays validation status: secure, insecure,
|
||||
bogus (security failure).
|
||||
.sp
|
||||
By default it reads no configuration file whatsoever.
|
||||
It attempts to reach the internet root servers.
|
||||
With \fI\%\-C\fP an unbound config file and with \fI\%\-r\fP \fBresolv.conf\fP
|
||||
can be read.
|
||||
.sp
|
||||
The available options are:
|
||||
.INDENT 0.0
|
||||
.TP
|
||||
.I hostname
|
||||
.B hostname
|
||||
This name is resolved (looked up in the DNS).
|
||||
If a IPv4 or IPv6 address is given, a reverse lookup is performed.
|
||||
.UNINDENT
|
||||
.INDENT 0.0
|
||||
.TP
|
||||
.B \-h
|
||||
Show the version and commandline option help.
|
||||
.UNINDENT
|
||||
.INDENT 0.0
|
||||
.TP
|
||||
.B \-v
|
||||
Enable verbose output and it shows validation results, on every line.
|
||||
Secure means that the NXDOMAIN (no such domain name), nodata (no such data)
|
||||
or positive data response validated correctly with one of the keys.
|
||||
Secure means that the NXDOMAIN (no such domain name), nodata (no such
|
||||
data) or positive data response validated correctly with one of the
|
||||
keys.
|
||||
Insecure means that that domain name has no security set up for it.
|
||||
Bogus (security failure) means that the response failed one or more checks,
|
||||
it is likely wrong, outdated, tampered with, or broken.
|
||||
Bogus (security failure) means that the response failed one or more
|
||||
checks, it is likely wrong, outdated, tampered with, or broken.
|
||||
.UNINDENT
|
||||
.INDENT 0.0
|
||||
.TP
|
||||
.B \-d
|
||||
Enable debug output to stderr. One \-d shows what the resolver and validator
|
||||
are doing and may tell you what is going on. More times, \-d \-d, gives a
|
||||
lot of output, with every packet sent and received.
|
||||
Enable debug output to stderr.
|
||||
One \fI\%\-d\fP shows what the resolver and validator are doing and may
|
||||
tell you what is going on.
|
||||
More times, \fI\%\-d\fP \fI\%\-d\fP, gives a lot of output, with every
|
||||
packet sent and received.
|
||||
.UNINDENT
|
||||
.INDENT 0.0
|
||||
.TP
|
||||
.B \-c \fIclass
|
||||
Specify the class to lookup for, the default is IN the internet class.
|
||||
.B \-c <class>
|
||||
Specify the class to lookup for, the default is IN the internet
|
||||
class.
|
||||
.UNINDENT
|
||||
.INDENT 0.0
|
||||
.TP
|
||||
.B \-t \fItype
|
||||
Specify the type of data to lookup. The default looks for IPv4, IPv6 and
|
||||
mail handler data, or domain name pointers for reverse queries.
|
||||
.B \-t <type>
|
||||
Specify the type of data to lookup.
|
||||
The default looks for IPv4, IPv6 and mail handler data, or domain name
|
||||
pointers for reverse queries.
|
||||
.UNINDENT
|
||||
.INDENT 0.0
|
||||
.TP
|
||||
.B \-y \fIkey
|
||||
Specify a public key to use as trust anchor. This is the base for a chain
|
||||
of trust that is built up from the trust anchor to the response, in order
|
||||
to validate the response message. Can be given as a DS or DNSKEY record.
|
||||
For example \-y "example.com DS 31560 5 1 1CFED84787E6E19CCF9372C1187325972FE546CD".
|
||||
.B \-y <key>
|
||||
Specify a public key to use as trust anchor.
|
||||
This is the base for a chain of trust that is built up from the trust
|
||||
anchor to the response, in order to validate the response message.
|
||||
Can be given as a DS or DNSKEY record.
|
||||
For example:
|
||||
.INDENT 7.0
|
||||
.INDENT 3.5
|
||||
.sp
|
||||
.nf
|
||||
.ft C
|
||||
\-y \(dqexample.com DS 31560 5 1 1CFED84787E6E19CCF9372C1187325972FE546CD\(dq
|
||||
.ft P
|
||||
.fi
|
||||
.UNINDENT
|
||||
.UNINDENT
|
||||
.UNINDENT
|
||||
.INDENT 0.0
|
||||
.TP
|
||||
.B \-D
|
||||
Enables DNSSEC validation. Reads the root anchor from the default configured
|
||||
root anchor at the default location, \fI@UNBOUND_ROOTKEY_FILE@\fR.
|
||||
Enables DNSSEC validation.
|
||||
Reads the root anchor from the default configured root anchor at the
|
||||
default location, \fB@UNBOUND_ROOTKEY_FILE@\fP\&.
|
||||
.UNINDENT
|
||||
.INDENT 0.0
|
||||
.TP
|
||||
.B \-f \fIkeyfile
|
||||
Reads keys from a file. Every line has a DS or DNSKEY record, in the format
|
||||
as for \-y. The zone file format, the same as dig and drill produce.
|
||||
.B \-f <keyfile>
|
||||
Reads keys from a file.
|
||||
Every line has a DS or DNSKEY record, in the format as for \fI\%\-y\fP\&.
|
||||
The zone file format, the same as \fBdig\fP and \fBdrill\fP produce.
|
||||
.UNINDENT
|
||||
.INDENT 0.0
|
||||
.TP
|
||||
.B \-F \fInamedkeyfile
|
||||
Reads keys from a BIND\-style named.conf file. Only the trusted\-key {}; entries
|
||||
are read.
|
||||
.B \-F <namedkeyfile>
|
||||
Reads keys from a BIND\-style \fBnamed.conf\fP file.
|
||||
Only the \fBtrusted\-key {};\fP entries are read.
|
||||
.UNINDENT
|
||||
.INDENT 0.0
|
||||
.TP
|
||||
.B \-C \fIconfigfile
|
||||
Uses the specified unbound.conf to prime
|
||||
.IR libunbound (3).
|
||||
.B \-C <configfile>
|
||||
Uses the specified unbound.conf to prime \fI\%libunbound(3)\fP\&.
|
||||
Pass it as first argument if you want to override some options from the
|
||||
config file with further arguments on the commandline.
|
||||
.UNINDENT
|
||||
.INDENT 0.0
|
||||
.TP
|
||||
.B \-r
|
||||
Read /etc/resolv.conf, and use the forward DNS servers from there (those could
|
||||
have been set by DHCP). More info in
|
||||
.IR resolv.conf (5).
|
||||
Read \fB/etc/resolv.conf\fP, and use the forward DNS servers from
|
||||
there (those could have been set by DHCP).
|
||||
More info in \fIresolv.conf(5)\fP\&.
|
||||
Breaks validation if those servers do not support DNSSEC.
|
||||
.UNINDENT
|
||||
.INDENT 0.0
|
||||
.TP
|
||||
.B \-4
|
||||
Use solely the IPv4 network for sending packets.
|
||||
.UNINDENT
|
||||
.INDENT 0.0
|
||||
.TP
|
||||
.B \-6
|
||||
Use solely the IPv6 network for sending packets.
|
||||
.SH "EXAMPLES"
|
||||
Some examples of use. The keys shown below are fakes, thus a security failure
|
||||
is encountered.
|
||||
.P
|
||||
.UNINDENT
|
||||
.SH EXAMPLES
|
||||
.sp
|
||||
Some examples of use.
|
||||
The keys shown below are fakes, thus a security failure is encountered.
|
||||
.INDENT 0.0
|
||||
.INDENT 3.5
|
||||
.sp
|
||||
.nf
|
||||
.ft C
|
||||
$ unbound\-host www.example.com
|
||||
.P
|
||||
$ unbound\-host \-v \-y "example.com DS 31560 5 1 1CFED84787E6E19CCF9372C1187325972FE546CD" www.example.com
|
||||
.P
|
||||
$ unbound\-host \-v \-y "example.com DS 31560 5 1 1CFED84787E6E19CCF9372C1187325972FE546CD" 192.0.2.153
|
||||
.SH "EXIT CODE"
|
||||
The unbound\-host program exits with status code 1 on error,
|
||||
0 on no error. The data may not be available on exit code 0, exit code 1
|
||||
means the lookup encountered a fatal error.
|
||||
.SH "SEE ALSO"
|
||||
\fIunbound.conf\fR(5),
|
||||
\fIunbound\fR(8).
|
||||
|
||||
$ unbound\-host \-v \-y \(dqexample.com DS 31560 5 1 1CFED84787E6E19CCF9372C1187325972FE546CD\(dq www.example.com
|
||||
|
||||
$ unbound\-host \-v \-y \(dqexample.com DS 31560 5 1 1CFED84787E6E19CCF9372C1187325972FE546CD\(dq 192.0.2.153
|
||||
.ft P
|
||||
.fi
|
||||
.UNINDENT
|
||||
.UNINDENT
|
||||
.SH EXIT CODE
|
||||
.sp
|
||||
The \fBunbound\-host\fP program exits with status code 1 on error, 0 on no error.
|
||||
The data may not be available on exit code 0, exit code 1 means the lookup
|
||||
encountered a fatal error.
|
||||
.SH SEE ALSO
|
||||
.sp
|
||||
\fI\%unbound.conf(5)\fP,
|
||||
\fI\%unbound(8)\fP\&.
|
||||
.SH AUTHOR
|
||||
Unbound developers are mentioned in the CREDITS file in the distribution.
|
||||
.SH COPYRIGHT
|
||||
1999-2026, NLnet Labs
|
||||
.\" Generated by docutils manpage writer.
|
||||
.
|
||||
|
||||
@@ -0,0 +1,176 @@
|
||||
..
|
||||
WHEN EDITING MAKE SURE EACH SENTENCE STARTS ON A NEW LINE
|
||||
|
||||
..
|
||||
IT HELPS RENDERERS TO DO THE RIGHT THING WRT SPACE
|
||||
|
||||
..
|
||||
IT HELPS PEOPLE DIFFING THE CHANGES
|
||||
|
||||
..
|
||||
WHEN EDITING MAKE SURE EACH SENTENCE STARTS ON A NEW LINE
|
||||
|
||||
..
|
||||
IT HELPS RENDERERS TO DO THE RIGHT THING WRT SPACE
|
||||
|
||||
..
|
||||
IT HELPS PEOPLE DIFFING THE CHANGES
|
||||
|
||||
..
|
||||
WHEN EDITING MAKE SURE EACH SENTENCE STARTS ON A NEW LINE
|
||||
|
||||
..
|
||||
IT HELPS RENDERERS TO DO THE RIGHT THING WRT SPACE
|
||||
|
||||
..
|
||||
IT HELPS PEOPLE DIFFING THE CHANGES
|
||||
|
||||
..
|
||||
WHEN EDITING MAKE SURE EACH SENTENCE STARTS ON A NEW LINE
|
||||
|
||||
..
|
||||
IT HELPS RENDERERS TO DO THE RIGHT THING WRT SPACE
|
||||
|
||||
..
|
||||
IT HELPS PEOPLE DIFFING THE CHANGES
|
||||
|
||||
.. program:: unbound-host
|
||||
|
||||
unbound-host(1)
|
||||
===============
|
||||
|
||||
Synopsis
|
||||
--------
|
||||
|
||||
**unbound-host** [``-C configfile``] [``-vdhr46D``] [``-c class``]
|
||||
[``-t type``] [``-y key``] [``-f keyfile``] [``-F namedkeyfile``] hostname
|
||||
|
||||
Description
|
||||
-----------
|
||||
|
||||
``unbound-host`` uses the Unbound validating resolver to query for the hostname
|
||||
and display results.
|
||||
With the :option:`-v` option it displays validation status: secure, insecure,
|
||||
bogus (security failure).
|
||||
|
||||
By default it reads no configuration file whatsoever.
|
||||
It attempts to reach the internet root servers.
|
||||
With :option:`-C` an unbound config file and with :option:`-r` ``resolv.conf``
|
||||
can be read.
|
||||
|
||||
The available options are:
|
||||
|
||||
.. option:: hostname
|
||||
|
||||
This name is resolved (looked up in the DNS).
|
||||
If a IPv4 or IPv6 address is given, a reverse lookup is performed.
|
||||
|
||||
.. option:: -h
|
||||
|
||||
Show the version and commandline option help.
|
||||
|
||||
.. option:: -v
|
||||
|
||||
Enable verbose output and it shows validation results, on every line.
|
||||
Secure means that the NXDOMAIN (no such domain name), nodata (no such
|
||||
data) or positive data response validated correctly with one of the
|
||||
keys.
|
||||
Insecure means that that domain name has no security set up for it.
|
||||
Bogus (security failure) means that the response failed one or more
|
||||
checks, it is likely wrong, outdated, tampered with, or broken.
|
||||
|
||||
.. option:: -d
|
||||
|
||||
Enable debug output to stderr.
|
||||
One :option:`-d` shows what the resolver and validator are doing and may
|
||||
tell you what is going on.
|
||||
More times, :option:`-d` :option:`-d`, gives a lot of output, with every
|
||||
packet sent and received.
|
||||
|
||||
.. option:: -c <class>
|
||||
|
||||
Specify the class to lookup for, the default is IN the internet
|
||||
class.
|
||||
|
||||
.. option:: -t <type>
|
||||
|
||||
Specify the type of data to lookup.
|
||||
The default looks for IPv4, IPv6 and mail handler data, or domain name
|
||||
pointers for reverse queries.
|
||||
|
||||
.. option:: -y <key>
|
||||
|
||||
Specify a public key to use as trust anchor.
|
||||
This is the base for a chain of trust that is built up from the trust
|
||||
anchor to the response, in order to validate the response message.
|
||||
Can be given as a DS or DNSKEY record.
|
||||
For example:
|
||||
|
||||
.. code-block:: text
|
||||
|
||||
-y "example.com DS 31560 5 1 1CFED84787E6E19CCF9372C1187325972FE546CD"
|
||||
|
||||
.. option:: -D
|
||||
|
||||
Enables DNSSEC validation.
|
||||
Reads the root anchor from the default configured root anchor at the
|
||||
default location, :file:`@UNBOUND_ROOTKEY_FILE@`.
|
||||
|
||||
.. option:: -f <keyfile>
|
||||
|
||||
Reads keys from a file.
|
||||
Every line has a DS or DNSKEY record, in the format as for :option:`-y`.
|
||||
The zone file format, the same as ``dig`` and ``drill`` produce.
|
||||
|
||||
.. option:: -F <namedkeyfile>
|
||||
|
||||
Reads keys from a BIND-style :file:`named.conf` file.
|
||||
Only the ``trusted-key {};`` entries are read.
|
||||
|
||||
.. option:: -C <configfile>
|
||||
|
||||
Uses the specified unbound.conf to prime :doc:`libunbound(3)</manpages/libunbound>`.
|
||||
Pass it as first argument if you want to override some options from the
|
||||
config file with further arguments on the commandline.
|
||||
|
||||
.. option:: -r
|
||||
|
||||
Read :file:`/etc/resolv.conf`, and use the forward DNS servers from
|
||||
there (those could have been set by DHCP).
|
||||
More info in *resolv.conf(5)*.
|
||||
Breaks validation if those servers do not support DNSSEC.
|
||||
|
||||
.. option:: -4
|
||||
|
||||
Use solely the IPv4 network for sending packets.
|
||||
|
||||
.. option:: -6
|
||||
|
||||
Use solely the IPv6 network for sending packets.
|
||||
|
||||
Examples
|
||||
--------
|
||||
|
||||
Some examples of use.
|
||||
The keys shown below are fakes, thus a security failure is encountered.
|
||||
|
||||
.. code-block:: text
|
||||
|
||||
$ unbound-host www.example.com
|
||||
|
||||
$ unbound-host -v -y "example.com DS 31560 5 1 1CFED84787E6E19CCF9372C1187325972FE546CD" www.example.com
|
||||
|
||||
$ unbound-host -v -y "example.com DS 31560 5 1 1CFED84787E6E19CCF9372C1187325972FE546CD" 192.0.2.153
|
||||
|
||||
Exit Code
|
||||
---------
|
||||
|
||||
The ``unbound-host`` program exits with status code 1 on error, 0 on no error.
|
||||
The data may not be available on exit code 0, exit code 1 means the lookup
|
||||
encountered a fatal error.
|
||||
|
||||
See Also
|
||||
--------
|
||||
|
||||
:doc:`unbound.conf(5)</manpages/unbound.conf>`,
|
||||
:doc:`unbound(8)</manpages/unbound>`.
|
||||
+102
-67
@@ -1,88 +1,123 @@
|
||||
.TH "unbound" "8" "@date@" "NLnet Labs" "unbound @version@"
|
||||
.\"
|
||||
.\" unbound.8 -- unbound manual
|
||||
.\"
|
||||
.\" Copyright (c) 2007, NLnet Labs. All rights reserved.
|
||||
.\"
|
||||
.\" See LICENSE for the license.
|
||||
.\"
|
||||
.\"
|
||||
.SH "NAME"
|
||||
.B unbound
|
||||
\- Unbound DNS validating resolver @version@.
|
||||
.SH "SYNOPSIS"
|
||||
.B unbound
|
||||
.RB [ \-h ]
|
||||
.RB [ \-d ]
|
||||
.RB [ \-p ]
|
||||
.RB [ \-v ]
|
||||
.RB [ \-c
|
||||
.IR cfgfile ]
|
||||
.SH "DESCRIPTION"
|
||||
.B Unbound
|
||||
is a caching DNS resolver.
|
||||
.P
|
||||
It uses a built in list of authoritative nameservers for the root zone (.),
|
||||
.\" Man page generated from reStructuredText.
|
||||
.
|
||||
.
|
||||
.nr rst2man-indent-level 0
|
||||
.
|
||||
.de1 rstReportMargin
|
||||
\\$1 \\n[an-margin]
|
||||
level \\n[rst2man-indent-level]
|
||||
level margin: \\n[rst2man-indent\\n[rst2man-indent-level]]
|
||||
-
|
||||
\\n[rst2man-indent0]
|
||||
\\n[rst2man-indent1]
|
||||
\\n[rst2man-indent2]
|
||||
..
|
||||
.de1 INDENT
|
||||
.\" .rstReportMargin pre:
|
||||
. RS \\$1
|
||||
. nr rst2man-indent\\n[rst2man-indent-level] \\n[an-margin]
|
||||
. nr rst2man-indent-level +1
|
||||
.\" .rstReportMargin post:
|
||||
..
|
||||
.de UNINDENT
|
||||
. RE
|
||||
.\" indent \\n[an-margin]
|
||||
.\" old: \\n[rst2man-indent\\n[rst2man-indent-level]]
|
||||
.nr rst2man-indent-level -1
|
||||
.\" new: \\n[rst2man-indent\\n[rst2man-indent-level]]
|
||||
.in \\n[rst2man-indent\\n[rst2man-indent-level]]u
|
||||
..
|
||||
.TH "UNBOUND" "8" "@date@" "@version@" "Unbound"
|
||||
.SH NAME
|
||||
unbound \- Unbound DNS validating resolver @version@.
|
||||
.SH SYNOPSIS
|
||||
.sp
|
||||
\fBunbound\fP [\fB\-hdpVv\fP] [\fB\-c <cfgfile>\fP]
|
||||
.SH DESCRIPTION
|
||||
.sp
|
||||
\fBunbound\fP is a caching DNS resolver.
|
||||
.sp
|
||||
It uses a built in list of authoritative nameservers for the root zone (\fB\&.\fP),
|
||||
the so called root hints.
|
||||
On receiving a DNS query it will ask the root nameservers for
|
||||
an answer and will in almost all cases receive a delegation to a top level
|
||||
domain (TLD) authoritative nameserver.
|
||||
On receiving a DNS query it will ask the root nameservers for an answer and
|
||||
will in almost all cases receive a delegation to a top level domain (TLD)
|
||||
authoritative nameserver.
|
||||
It will then ask that nameserver for an answer.
|
||||
It will recursively continue until an answer is found or no answer is
|
||||
available (NXDOMAIN).
|
||||
For performance and efficiency reasons that answer is cached for a
|
||||
certain time (the answer's time\-to\-live or TTL).
|
||||
It will recursively continue until an answer is found or no answer is available
|
||||
(NXDOMAIN).
|
||||
For performance and efficiency reasons that answer is cached for a certain time
|
||||
(the answer\(aqs time\-to\-live or TTL).
|
||||
A second query for the same name will then be answered from the cache.
|
||||
Unbound can also do DNSSEC validation.
|
||||
.P
|
||||
To use a locally running
|
||||
.B Unbound
|
||||
for resolving put
|
||||
.sp
|
||||
.RS 6n
|
||||
To use a locally running Unbound for resolving put:
|
||||
.INDENT 0.0
|
||||
.INDENT 3.5
|
||||
.sp
|
||||
.nf
|
||||
.ft C
|
||||
nameserver 127.0.0.1
|
||||
.RE
|
||||
.ft P
|
||||
.fi
|
||||
.UNINDENT
|
||||
.UNINDENT
|
||||
.sp
|
||||
into \fIresolv.conf(5)\fP\&.
|
||||
.sp
|
||||
If authoritative DNS is needed as well using \fI\%nsd(8)\fP,
|
||||
careful setup is required because authoritative nameservers and resolvers are
|
||||
using the same port number (53).
|
||||
.sp
|
||||
into
|
||||
.IR resolv.conf (5).
|
||||
.P
|
||||
If authoritative DNS is needed as well using
|
||||
.IR nsd (8),
|
||||
careful setup is required because authoritative nameservers and
|
||||
resolvers are using the same port number (53).
|
||||
.P
|
||||
The available options are:
|
||||
.INDENT 0.0
|
||||
.TP
|
||||
.B \-h
|
||||
Show the version number and commandline option help, and exit.
|
||||
.UNINDENT
|
||||
.INDENT 0.0
|
||||
.TP
|
||||
.B \-c\fI cfgfile
|
||||
Set the config file with settings for Unbound to read instead of reading the
|
||||
file at the default location, @ub_conf_file@. The syntax is
|
||||
described in \fIunbound.conf\fR(5).
|
||||
.B \-c <cfgfile>
|
||||
Set the config file with settings for unbound to read instead of reading the
|
||||
file at the default location, \fB@ub_conf_file@\fP\&.
|
||||
The syntax is described in \fI\%unbound.conf(5)\fP\&.
|
||||
.UNINDENT
|
||||
.INDENT 0.0
|
||||
.TP
|
||||
.B \-d
|
||||
Debug flag: do not fork into the background, but stay attached to
|
||||
the console. This flag will also delay writing to the log file until
|
||||
the thread\-spawn time, so that most config and setup errors appear on
|
||||
stderr. If given twice or more, logging does not switch to the log file
|
||||
or to syslog, but the log messages are printed to stderr all the time.
|
||||
Debug flag: do not fork into the background, but stay attached to the
|
||||
console.
|
||||
This flag will also delay writing to the log file until the thread\-spawn
|
||||
time, so that most config and setup errors appear on stderr.
|
||||
If given twice or more, logging does not switch to the log file or to
|
||||
syslog, but the log messages are printed to stderr all the time.
|
||||
.UNINDENT
|
||||
.INDENT 0.0
|
||||
.TP
|
||||
.B \-p
|
||||
Don't use a pidfile. This argument should only be used by supervision
|
||||
systems which can ensure that only one instance of Unbound will run
|
||||
concurrently.
|
||||
Don\(aqt use a pidfile.
|
||||
This argument should only be used by supervision systems which can ensure
|
||||
that only one instance of Unbound will run concurrently.
|
||||
.UNINDENT
|
||||
.INDENT 0.0
|
||||
.TP
|
||||
.B \-v
|
||||
Increase verbosity. If given multiple times, more information is logged.
|
||||
This is added to the verbosity (if any) from the config file.
|
||||
Increase verbosity.
|
||||
If given multiple times, more information is logged.
|
||||
This is in addition to the verbosity (if any) from the config file.
|
||||
.UNINDENT
|
||||
.INDENT 0.0
|
||||
.TP
|
||||
.B \-V
|
||||
Show the version number and build options, and exit.
|
||||
.SH "SEE ALSO"
|
||||
\fIunbound.conf\fR(5),
|
||||
\fIunbound\-checkconf\fR(8),
|
||||
\fInsd\fR(8).
|
||||
.SH "AUTHORS"
|
||||
.B Unbound
|
||||
developers are mentioned in the CREDITS file in the distribution.
|
||||
.UNINDENT
|
||||
.SH SEE ALSO
|
||||
.sp
|
||||
\fI\%unbound.conf(5)\fP,
|
||||
\fI\%unbound\-checkconf(8)\fP,
|
||||
\fI\%nsd(8)\fP\&.
|
||||
.SH AUTHOR
|
||||
Unbound developers are mentioned in the CREDITS file in the distribution.
|
||||
.SH COPYRIGHT
|
||||
1999-2026, NLnet Labs
|
||||
.\" Generated by docutils manpage writer.
|
||||
.
|
||||
|
||||
+5423
-2557
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
+119
@@ -0,0 +1,119 @@
|
||||
..
|
||||
WHEN EDITING MAKE SURE EACH SENTENCE STARTS ON A NEW LINE
|
||||
|
||||
..
|
||||
IT HELPS RENDERERS TO DO THE RIGHT THING WRT SPACE
|
||||
|
||||
..
|
||||
IT HELPS PEOPLE DIFFING THE CHANGES
|
||||
|
||||
..
|
||||
WHEN EDITING MAKE SURE EACH SENTENCE STARTS ON A NEW LINE
|
||||
|
||||
..
|
||||
IT HELPS RENDERERS TO DO THE RIGHT THING WRT SPACE
|
||||
|
||||
..
|
||||
IT HELPS PEOPLE DIFFING THE CHANGES
|
||||
|
||||
..
|
||||
WHEN EDITING MAKE SURE EACH SENTENCE STARTS ON A NEW LINE
|
||||
|
||||
..
|
||||
IT HELPS RENDERERS TO DO THE RIGHT THING WRT SPACE
|
||||
|
||||
..
|
||||
IT HELPS PEOPLE DIFFING THE CHANGES
|
||||
|
||||
..
|
||||
WHEN EDITING MAKE SURE EACH SENTENCE STARTS ON A NEW LINE
|
||||
|
||||
..
|
||||
IT HELPS RENDERERS TO DO THE RIGHT THING WRT SPACE
|
||||
|
||||
..
|
||||
IT HELPS PEOPLE DIFFING THE CHANGES
|
||||
|
||||
.. program:: unbound
|
||||
|
||||
unbound(8)
|
||||
==========
|
||||
|
||||
Synopsis
|
||||
--------
|
||||
|
||||
**unbound** [``-hdpVv``] [``-c <cfgfile>``]
|
||||
|
||||
Description
|
||||
-----------
|
||||
|
||||
``unbound`` is a caching DNS resolver.
|
||||
|
||||
It uses a built in list of authoritative nameservers for the root zone (``.``),
|
||||
the so called root hints.
|
||||
On receiving a DNS query it will ask the root nameservers for an answer and
|
||||
will in almost all cases receive a delegation to a top level domain (TLD)
|
||||
authoritative nameserver.
|
||||
It will then ask that nameserver for an answer.
|
||||
It will recursively continue until an answer is found or no answer is available
|
||||
(NXDOMAIN).
|
||||
For performance and efficiency reasons that answer is cached for a certain time
|
||||
(the answer's time-to-live or TTL).
|
||||
A second query for the same name will then be answered from the cache.
|
||||
Unbound can also do DNSSEC validation.
|
||||
|
||||
To use a locally running Unbound for resolving put:
|
||||
|
||||
.. code-block:: text
|
||||
|
||||
nameserver 127.0.0.1
|
||||
|
||||
into *resolv.conf(5)*.
|
||||
|
||||
If authoritative DNS is needed as well using :external+nsd:doc:`manpages/nsd`,
|
||||
careful setup is required because authoritative nameservers and resolvers are
|
||||
using the same port number (53).
|
||||
|
||||
The available options are:
|
||||
|
||||
.. option:: -h
|
||||
|
||||
Show the version number and commandline option help, and exit.
|
||||
|
||||
.. option:: -c <cfgfile>
|
||||
|
||||
Set the config file with settings for unbound to read instead of reading the
|
||||
file at the default location, :file:`@ub_conf_file@`.
|
||||
The syntax is described in :doc:`unbound.conf(5)</manpages/unbound.conf>`.
|
||||
|
||||
.. option:: -d
|
||||
|
||||
Debug flag: do not fork into the background, but stay attached to the
|
||||
console.
|
||||
This flag will also delay writing to the log file until the thread-spawn
|
||||
time, so that most config and setup errors appear on stderr.
|
||||
If given twice or more, logging does not switch to the log file or to
|
||||
syslog, but the log messages are printed to stderr all the time.
|
||||
|
||||
.. option:: -p
|
||||
|
||||
Don't use a pidfile.
|
||||
This argument should only be used by supervision systems which can ensure
|
||||
that only one instance of Unbound will run concurrently.
|
||||
|
||||
.. option:: -v
|
||||
|
||||
Increase verbosity.
|
||||
If given multiple times, more information is logged.
|
||||
This is in addition to the verbosity (if any) from the config file.
|
||||
|
||||
.. option:: -V
|
||||
|
||||
Show the version number and build options, and exit.
|
||||
|
||||
See Also
|
||||
--------
|
||||
|
||||
:doc:`unbound.conf(5)</manpages/unbound.conf>`,
|
||||
:doc:`unbound-checkconf(8)</manpages/unbound-checkconf>`,
|
||||
:external+nsd:doc:`manpages/nsd`.
|
||||
@@ -459,6 +459,7 @@ addrtree_insert(struct addrtree *tree, const addrkey_t *addr,
|
||||
/* Data is stored in other leafnode */
|
||||
node = newnode;
|
||||
newnode = node_create(tree, elem, scope, ttl);
|
||||
if (!newnode) return;
|
||||
if (!edge_create(newnode, addr, sourcemask, node,
|
||||
index^1)) {
|
||||
clean_node(tree, newnode);
|
||||
|
||||
@@ -116,7 +116,7 @@ struct addredge {
|
||||
addrlen_t len;
|
||||
/** child node this edge is connected to */
|
||||
struct addrnode *node;
|
||||
/** Parent node this ege is connected to */
|
||||
/** Parent node this edge is connected to */
|
||||
struct addrnode *parent_node;
|
||||
/** Index of this edge in parent_node */
|
||||
int parent_index;
|
||||
|
||||
+267
-17
@@ -51,6 +51,7 @@
|
||||
#include "services/cache/dns.h"
|
||||
#include "util/module.h"
|
||||
#include "util/regional.h"
|
||||
#include "util/fptr_wlist.h"
|
||||
#include "util/storage/slabhash.h"
|
||||
#include "util/config_file.h"
|
||||
#include "util/data/msgreply.h"
|
||||
@@ -69,6 +70,7 @@ subnet_data_delete(void *d, void *ATTR_UNUSED(arg))
|
||||
r = (struct subnet_msg_cache_data*)d;
|
||||
addrtree_delete(r->tree4);
|
||||
addrtree_delete(r->tree6);
|
||||
free(r->reason_fail);
|
||||
free(r);
|
||||
}
|
||||
|
||||
@@ -83,6 +85,8 @@ msg_cache_sizefunc(void *k, void *d)
|
||||
+ q->key.qname_len + lock_get_mem(&q->entry.lock);
|
||||
s += addrtree_size(r->tree4);
|
||||
s += addrtree_size(r->tree6);
|
||||
if(r->reason_fail)
|
||||
s += strlen(r->reason_fail)+1;
|
||||
return s;
|
||||
}
|
||||
|
||||
@@ -153,9 +157,32 @@ int ecs_whitelist_check(struct query_info* qinfo,
|
||||
return 1;
|
||||
sn_env = (struct subnet_env*)qstate->env->modinfo[id];
|
||||
|
||||
if(sq->is_subquery_nonsubnet) {
|
||||
if(sq->is_subquery_scopezero) {
|
||||
/* Check if the result can be stored in the global cache,
|
||||
* this is okay if the address and name are not configured
|
||||
* as subnet address and subnet zone. */
|
||||
if(!ecs_is_whitelisted(sn_env->whitelist,
|
||||
addr, addrlen, qinfo->qname, qinfo->qname_len,
|
||||
qinfo->qclass)) {
|
||||
/* The stub or forward can have no_cache set.*/
|
||||
if(iter_stub_fwd_no_cache(qstate, &qstate->qinfo, NULL, NULL, NULL, 0)) {
|
||||
verbose(VERB_ALGO, "subnet subquery is not stored globally, stuborfwd is no_cache");
|
||||
} else {
|
||||
verbose(VERB_ALGO, "subnet store subquery global, name and addr have no subnet treatment.%s",
|
||||
(sq->started_no_cache_store?
|
||||
" But the subnet module was started with no_cache_store for the super query, and that is still applied to this query":""));
|
||||
qstate->no_cache_store = sq->started_no_cache_store;
|
||||
}
|
||||
}
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
/* Cache by default, might be disabled after parsing EDNS option
|
||||
* received from nameserver. */
|
||||
if(!iter_stub_fwd_no_cache(qstate, &qstate->qinfo, NULL, NULL, NULL, 0)) {
|
||||
if(!iter_stub_fwd_no_cache(qstate, &qstate->qinfo, NULL, NULL, NULL, 0)
|
||||
&& sq->ecs_client_in.subnet_validdata) {
|
||||
qstate->no_cache_store = 0;
|
||||
}
|
||||
|
||||
@@ -176,12 +203,18 @@ int ecs_whitelist_check(struct query_info* qinfo,
|
||||
if(sq->ecs_server_out.subnet_source_mask == 0) {
|
||||
sq->subnet_sent_no_subnet = 1;
|
||||
sq->subnet_sent = 0;
|
||||
/* The result should end up in subnet cache,
|
||||
* not in global cache. */
|
||||
qstate->no_cache_store = 1;
|
||||
return 1;
|
||||
}
|
||||
subnet_ecs_opt_list_append(&sq->ecs_server_out,
|
||||
&qstate->edns_opts_back_out, qstate, region);
|
||||
}
|
||||
sq->subnet_sent = 1;
|
||||
/* Do not store servfails in global cache, since the subnet
|
||||
* option is sent out. */
|
||||
qstate->no_cache_store = 1;
|
||||
}
|
||||
else {
|
||||
/* Outgoing ECS option is set, but we don't want to sent it to
|
||||
@@ -232,13 +265,13 @@ subnetmod_init(struct module_env *env, int id)
|
||||
HASH_DEFAULT_STARTARRAY, env->cfg->msg_cache_size,
|
||||
msg_cache_sizefunc, query_info_compare, query_entry_delete,
|
||||
subnet_data_delete, NULL);
|
||||
slabhash_setmarkdel(sn_env->subnet_msg_cache, &subnet_markdel);
|
||||
if(!sn_env->subnet_msg_cache) {
|
||||
log_err("subnetcache: could not create cache");
|
||||
free(sn_env);
|
||||
env->modinfo[id] = NULL;
|
||||
return 0;
|
||||
}
|
||||
slabhash_setmarkdel(sn_env->subnet_msg_cache, &subnet_markdel);
|
||||
/* whitelist for edns subnet capable servers */
|
||||
sn_env->whitelist = ecs_whitelist_create();
|
||||
if(!sn_env->whitelist ||
|
||||
@@ -403,6 +436,35 @@ update_cache(struct module_qstate *qstate, int id)
|
||||
}
|
||||
/* lru_entry->lock is locked regardless of how we got here,
|
||||
* either from the slabhash_lookup, or above in the new allocated */
|
||||
if(!qstate->return_msg && qstate->error_response_cache) {
|
||||
struct subnet_msg_cache_data *data =
|
||||
(struct subnet_msg_cache_data*)lru_entry->data;
|
||||
data->ttl_servfail = *qstate->env->now + NORR_TTL;
|
||||
data->ede_fail = errinf_to_reason_bogus(qstate);
|
||||
diff_size = (data->reason_fail?strlen(data->reason_fail)+1:0);
|
||||
if(qstate->errinf) {
|
||||
char* str = errinf_to_str_misc(qstate);
|
||||
free(data->reason_fail);
|
||||
data->reason_fail = NULL;
|
||||
if(str)
|
||||
data->reason_fail = strdup(str);
|
||||
}
|
||||
diff_size = (data->reason_fail?strlen(data->reason_fail)+1:0)
|
||||
- diff_size;
|
||||
lock_rw_unlock(&lru_entry->lock);
|
||||
if (need_to_insert) {
|
||||
slabhash_insert(subnet_msg_cache, h, lru_entry,
|
||||
lru_entry->data, NULL);
|
||||
} else {
|
||||
slabhash_update_space_used(subnet_msg_cache, h, NULL,
|
||||
diff_size);
|
||||
}
|
||||
return;
|
||||
}
|
||||
if(!qstate->return_msg) {
|
||||
lock_rw_unlock(&lru_entry->lock);
|
||||
return;
|
||||
}
|
||||
/* Step 2, find the correct tree */
|
||||
if (!(tree = get_tree(lru_entry->data, edns, sne, qstate->env->cfg))) {
|
||||
lock_rw_unlock(&lru_entry->lock);
|
||||
@@ -446,6 +508,21 @@ update_cache(struct module_qstate *qstate, int id)
|
||||
}
|
||||
}
|
||||
|
||||
/** See if there is a stored servfail, returns true if so, and sets reply. */
|
||||
static int
|
||||
lookup_check_servfail(struct module_qstate *qstate,
|
||||
struct subnet_msg_cache_data *data)
|
||||
{
|
||||
struct module_env *env = qstate->env;
|
||||
if(!data)
|
||||
return 0;
|
||||
if(!data->ttl_servfail || TTL_IS_EXPIRED(data->ttl_servfail, *env->now))
|
||||
return 0;
|
||||
qstate->return_rcode = LDNS_RCODE_SERVFAIL;
|
||||
errinf_ede(qstate, data->reason_fail, data->ede_fail);
|
||||
return 1;
|
||||
}
|
||||
|
||||
/** Lookup in cache and reply true iff reply is sent. */
|
||||
static int
|
||||
lookup_and_reply(struct module_qstate *qstate, int id, struct subnet_qstate *sq, int prefetch)
|
||||
@@ -459,6 +536,8 @@ lookup_and_reply(struct module_qstate *qstate, int id, struct subnet_qstate *sq,
|
||||
struct addrtree *tree;
|
||||
struct addrnode *node;
|
||||
uint8_t scope;
|
||||
int must_validate = (!(qstate->query_flags&BIT_CD)
|
||||
|| qstate->env->cfg->ignore_cd) && qstate->env->need_to_validate;
|
||||
|
||||
memset(&sq->ecs_client_out, 0, sizeof(sq->ecs_client_out));
|
||||
|
||||
@@ -472,12 +551,20 @@ lookup_and_reply(struct module_qstate *qstate, int id, struct subnet_qstate *sq,
|
||||
tree = (ecs->subnet_addr_fam == EDNSSUBNET_ADDRFAM_IP4)?
|
||||
data->tree4 : data->tree6;
|
||||
if (!tree) { /* qinfo in cache but not for this family */
|
||||
if(lookup_check_servfail(qstate, data)) {
|
||||
lock_rw_unlock(&e->lock);
|
||||
return 1;
|
||||
}
|
||||
lock_rw_unlock(&e->lock);
|
||||
return 0;
|
||||
}
|
||||
node = addrtree_find(tree, (addrkey_t*)ecs->subnet_addr,
|
||||
ecs->subnet_source_mask, *env->now);
|
||||
if (!node) { /* plain old cache miss */
|
||||
if(lookup_check_servfail(qstate, data)) {
|
||||
lock_rw_unlock(&e->lock);
|
||||
return 1;
|
||||
}
|
||||
lock_rw_unlock(&e->lock);
|
||||
return 0;
|
||||
}
|
||||
@@ -486,12 +573,24 @@ lookup_and_reply(struct module_qstate *qstate, int id, struct subnet_qstate *sq,
|
||||
(struct reply_info *)node->elem, qstate->region, *env->now, 0,
|
||||
env->scratch);
|
||||
scope = (uint8_t)node->scope;
|
||||
lock_rw_unlock(&e->lock);
|
||||
|
||||
if (!qstate->return_msg) { /* Failed allocation or expired TTL */
|
||||
if(lookup_check_servfail(qstate, data)) {
|
||||
lock_rw_unlock(&e->lock);
|
||||
return 1;
|
||||
}
|
||||
lock_rw_unlock(&e->lock);
|
||||
return 0;
|
||||
}
|
||||
|
||||
lock_rw_unlock(&e->lock);
|
||||
if(qstate->return_msg->rep->security == sec_status_unchecked
|
||||
&& must_validate) {
|
||||
/* The message has to be validated first. */
|
||||
verbose(VERB_ALGO, "subnet: unchecked cache entry needs "
|
||||
"validation");
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (sq->subnet_downstream) { /* relay to interested client */
|
||||
sq->ecs_client_out.subnet_scope_mask = scope;
|
||||
sq->ecs_client_out.subnet_addr_fam = ecs->subnet_addr_fam;
|
||||
@@ -522,6 +621,87 @@ common_prefix(uint8_t *a, uint8_t *b, uint8_t net)
|
||||
return !memcmp(a, b, n) && ((net % 8) == 0 || a[n] == b[n]);
|
||||
}
|
||||
|
||||
/**
|
||||
* Create sub request that looks up the query.
|
||||
* @param qstate: query state
|
||||
* @param id: module id.
|
||||
* @param sq: subnet qstate
|
||||
* @return false on failure.
|
||||
*/
|
||||
static int
|
||||
generate_sub_request(struct module_qstate *qstate, int id, struct subnet_qstate* sq)
|
||||
{
|
||||
struct module_qstate* subq = NULL;
|
||||
uint16_t qflags = 0; /* OPCODE QUERY, no flags */
|
||||
int prime = 0;
|
||||
int valrec = 0;
|
||||
struct query_info qinf;
|
||||
qinf.qname = qstate->qinfo.qname;
|
||||
qinf.qname_len = qstate->qinfo.qname_len;
|
||||
qinf.qtype = qstate->qinfo.qtype;
|
||||
qinf.qclass = qstate->qinfo.qclass;
|
||||
qinf.local_alias = NULL;
|
||||
|
||||
qflags |= BIT_RD;
|
||||
if((qstate->query_flags & BIT_CD)!=0) {
|
||||
qflags |= BIT_CD;
|
||||
/* The valrec is left off. Leave out: valrec = 1;
|
||||
* So that the cache is protected with DNSSEC validation.
|
||||
* Just like the global cache. DNSSEC validation is performed
|
||||
* regardless of the setting of the querier's CD flag. */
|
||||
}
|
||||
|
||||
fptr_ok(fptr_whitelist_modenv_attach_sub(qstate->env->attach_sub));
|
||||
if(!(*qstate->env->attach_sub)(qstate, &qinf, qstate->client_info,
|
||||
qflags, prime, valrec, &subq)) {
|
||||
return 0;
|
||||
}
|
||||
if(subq) {
|
||||
/* It is possible to access the subquery module state. */
|
||||
struct subnet_qstate* subsq;
|
||||
if(!subnet_new_qstate(subq, id)) {
|
||||
verbose(VERB_ALGO, "Could not allocate new subnet qstate");
|
||||
return 0;
|
||||
}
|
||||
subsq = (struct subnet_qstate*)subq->minfo[id];
|
||||
subsq->is_subquery_nonsubnet = 1;
|
||||
subsq->started_no_cache_store = sq->started_no_cache_store;
|
||||
|
||||
/* When the client asks 0.0.0.0/0 and the name is not treated
|
||||
* as subnet, it is to be stored in the global cache.
|
||||
* Store that the client asked for that, if so. */
|
||||
if(sq->ecs_client_in.subnet_source_mask == 0 &&
|
||||
edns_opt_list_find(qstate->edns_opts_front_in,
|
||||
qstate->env->cfg->client_subnet_opcode)) {
|
||||
subq->no_cache_store = 1;
|
||||
subsq->is_subquery_scopezero = 1;
|
||||
}
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
/**
|
||||
* Perform the query without subnet
|
||||
* @param qstate: query state
|
||||
* @param id: module id.
|
||||
* @param sq: subnet qstate
|
||||
* @return module state
|
||||
*/
|
||||
static enum module_ext_state
|
||||
generate_lookup_without_subnet(struct module_qstate *qstate, int id,
|
||||
struct subnet_qstate* sq)
|
||||
{
|
||||
verbose(VERB_ALGO, "subnetcache: make subquery to look up without subnet");
|
||||
if(!generate_sub_request(qstate, id, sq)) {
|
||||
verbose(VERB_ALGO, "Could not generate sub query");
|
||||
qstate->return_rcode = LDNS_RCODE_SERVFAIL;
|
||||
qstate->return_msg = NULL;
|
||||
return module_finished;
|
||||
}
|
||||
sq->wait_subquery = 1;
|
||||
return module_wait_subquery;
|
||||
}
|
||||
|
||||
static enum module_ext_state
|
||||
eval_response(struct module_qstate *qstate, int id, struct subnet_qstate *sq)
|
||||
{
|
||||
@@ -538,6 +718,12 @@ eval_response(struct module_qstate *qstate, int id, struct subnet_qstate *sq)
|
||||
/* already an answer and its not a message, but retain
|
||||
* the actual rcode, instead of module_error, so send
|
||||
* module_finished */
|
||||
if(qstate->error_response_cache) {
|
||||
verbose(VERB_ALGO, "subnet: store error response");
|
||||
lock_rw_wrlock(&sne->biglock);
|
||||
update_cache(qstate, id);
|
||||
lock_rw_unlock(&sne->biglock);
|
||||
}
|
||||
return module_finished;
|
||||
}
|
||||
|
||||
@@ -557,14 +743,7 @@ eval_response(struct module_qstate *qstate, int id, struct subnet_qstate *sq)
|
||||
* is still useful to put it in the edns subnet cache for
|
||||
* when a client explicitly asks for subnet specific answer. */
|
||||
verbose(VERB_QUERY, "subnetcache: Authority indicates no support");
|
||||
if(!sq->started_no_cache_store) {
|
||||
lock_rw_wrlock(&sne->biglock);
|
||||
update_cache(qstate, id);
|
||||
lock_rw_unlock(&sne->biglock);
|
||||
}
|
||||
if (sq->subnet_downstream)
|
||||
cp_edns_bad_response(c_out, c_in);
|
||||
return module_finished;
|
||||
return generate_lookup_without_subnet(qstate, id, sq);
|
||||
}
|
||||
|
||||
/* Purposefully there was no sent subnet, and there is consequently
|
||||
@@ -589,14 +768,14 @@ eval_response(struct module_qstate *qstate, int id, struct subnet_qstate *sq)
|
||||
!common_prefix(s_out->subnet_addr, s_in->subnet_addr,
|
||||
s_out->subnet_source_mask))
|
||||
{
|
||||
/* we can not accept, restart query without option */
|
||||
/* we can not accept, perform query without option */
|
||||
verbose(VERB_QUERY, "subnetcache: forged data");
|
||||
s_out->subnet_validdata = 0;
|
||||
(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;
|
||||
return generate_lookup_without_subnet(qstate, id, sq);
|
||||
}
|
||||
|
||||
lock_rw_wrlock(&sne->biglock);
|
||||
@@ -794,6 +973,11 @@ ecs_edns_back_parsed(struct module_qstate* qstate, int id,
|
||||
sq->max_scope = sq->ecs_server_in.subnet_scope_mask;
|
||||
} else if(sq->subnet_sent_no_subnet) {
|
||||
/* The answer can be stored as scope 0, not in global cache. */
|
||||
/* This was already set in ecs_whitelist_check */
|
||||
qstate->no_cache_store = 1;
|
||||
} else if(sq->subnet_sent) {
|
||||
/* Need another query to be able to store in global cache. */
|
||||
/* This was already set in ecs_whitelist_check */
|
||||
qstate->no_cache_store = 1;
|
||||
}
|
||||
|
||||
@@ -812,6 +996,33 @@ subnetmod_operate(struct module_qstate *qstate, enum module_ev event,
|
||||
strmodulevent(event));
|
||||
log_query_info(VERB_QUERY, "subnetcache operate: query", &qstate->qinfo);
|
||||
|
||||
if(sq && sq->wait_subquery_done) {
|
||||
/* The subquery lookup returned. */
|
||||
if(sq->ecs_client_in.subnet_source_mask == 0 &&
|
||||
edns_opt_list_find(qstate->edns_opts_front_in,
|
||||
qstate->env->cfg->client_subnet_opcode)) {
|
||||
if(!sq->started_no_cache_store &&
|
||||
qstate->return_msg) {
|
||||
lock_rw_wrlock(&sne->biglock);
|
||||
update_cache(qstate, id);
|
||||
lock_rw_unlock(&sne->biglock);
|
||||
}
|
||||
if (sq->subnet_downstream)
|
||||
cp_edns_bad_response(&sq->ecs_client_out,
|
||||
&sq->ecs_client_in);
|
||||
/* It is a scope zero lookup, append edns subnet
|
||||
* option to the querier. */
|
||||
subnet_ecs_opt_list_append(&sq->ecs_client_out,
|
||||
&qstate->edns_opts_front_out, qstate,
|
||||
qstate->region);
|
||||
qstate->is_subnet_answer = 1;
|
||||
}
|
||||
sq->wait_subquery_done = 0;
|
||||
qstate->ext_state[id] = module_finished;
|
||||
qstate->no_cache_store = sq->started_no_cache_store;
|
||||
qstate->no_cache_lookup = sq->started_no_cache_lookup;
|
||||
return;
|
||||
}
|
||||
if((event == module_event_new || event == module_event_pass) &&
|
||||
sq == NULL) {
|
||||
struct edns_option* ecs_opt;
|
||||
@@ -822,6 +1033,8 @@ subnetmod_operate(struct module_qstate *qstate, enum module_ev event,
|
||||
}
|
||||
|
||||
sq = (struct subnet_qstate*)qstate->minfo[id];
|
||||
if(sq->wait_subquery)
|
||||
return; /* Wait for that subquery to return */
|
||||
|
||||
if((ecs_opt = edns_opt_list_find(
|
||||
qstate->edns_opts_front_in,
|
||||
@@ -851,6 +1064,14 @@ subnetmod_operate(struct module_qstate *qstate, enum module_ev event,
|
||||
/* No clients are interested in result or we could not
|
||||
* parse it, we don't do client subnet */
|
||||
sq->ecs_server_out.subnet_validdata = 0;
|
||||
if(edns_opt_list_find(qstate->edns_opts_front_in,
|
||||
qstate->env->cfg->client_subnet_opcode)) {
|
||||
/* aggregated this deaggregated state */
|
||||
qstate->ext_state[id] =
|
||||
generate_lookup_without_subnet(
|
||||
qstate, id, sq);
|
||||
return;
|
||||
}
|
||||
verbose(VERB_ALGO, "subnetcache: pass to next module");
|
||||
qstate->ext_state[id] = module_wait_module;
|
||||
return;
|
||||
@@ -874,6 +1095,7 @@ subnetmod_operate(struct module_qstate *qstate, enum module_ev event,
|
||||
qstate->env->cfg->prefetch)) {
|
||||
sne->num_msg_cache++;
|
||||
lock_rw_unlock(&sne->biglock);
|
||||
qstate->is_subnet_answer = 1;
|
||||
verbose(VERB_QUERY, "subnetcache: answered from cache");
|
||||
qstate->ext_state[id] = module_finished;
|
||||
|
||||
@@ -891,6 +1113,14 @@ subnetmod_operate(struct module_qstate *qstate, enum module_ev event,
|
||||
}
|
||||
lock_rw_unlock(&sne->biglock);
|
||||
}
|
||||
if(sq->ecs_client_in.subnet_source_mask == 0 &&
|
||||
edns_opt_list_find(qstate->edns_opts_front_in,
|
||||
qstate->env->cfg->client_subnet_opcode)) {
|
||||
/* client asked for resolution without edns subnet */
|
||||
qstate->ext_state[id] = generate_lookup_without_subnet(
|
||||
qstate, id, sq);
|
||||
return;
|
||||
}
|
||||
|
||||
sq->ecs_server_out.subnet_addr_fam =
|
||||
sq->ecs_client_in.subnet_addr_fam;
|
||||
@@ -927,6 +1157,8 @@ subnetmod_operate(struct module_qstate *qstate, enum module_ev event,
|
||||
qstate->ext_state[id] = module_wait_module;
|
||||
return;
|
||||
}
|
||||
if(sq && sq->wait_subquery)
|
||||
return; /* Wait for that subquery to return */
|
||||
/* Query handed back by next module, we have a 'final' answer */
|
||||
if(sq && event == module_event_moddone) {
|
||||
qstate->ext_state[id] = eval_response(qstate, id, sq);
|
||||
@@ -935,6 +1167,7 @@ subnetmod_operate(struct module_qstate *qstate, enum module_ev event,
|
||||
subnet_ecs_opt_list_append(&sq->ecs_client_out,
|
||||
&qstate->edns_opts_front_out, qstate,
|
||||
qstate->region);
|
||||
qstate->is_subnet_answer = 1;
|
||||
if(verbosity >= VERB_ALGO) {
|
||||
subnet_log_print("reply has edns subnet",
|
||||
edns_opt_list_find(
|
||||
@@ -975,10 +1208,27 @@ subnetmod_clear(struct module_qstate *ATTR_UNUSED(qstate),
|
||||
}
|
||||
|
||||
void
|
||||
subnetmod_inform_super(struct module_qstate *ATTR_UNUSED(qstate),
|
||||
int ATTR_UNUSED(id), struct module_qstate *ATTR_UNUSED(super))
|
||||
subnetmod_inform_super(struct module_qstate *qstate, int id,
|
||||
struct module_qstate *super)
|
||||
{
|
||||
/* Not used */
|
||||
struct subnet_qstate* super_sq =
|
||||
(struct subnet_qstate*)super->minfo[id];
|
||||
log_query_info(VERB_ALGO, "subnetcache inform_super: query",
|
||||
&super->qinfo);
|
||||
super_sq->wait_subquery = 0;
|
||||
super_sq->wait_subquery_done = 1;
|
||||
if(qstate->return_rcode != LDNS_RCODE_NOERROR ||
|
||||
!qstate->return_msg) {
|
||||
super->return_msg = NULL;
|
||||
super->return_rcode = LDNS_RCODE_SERVFAIL;
|
||||
return;
|
||||
}
|
||||
super->return_rcode = LDNS_RCODE_NOERROR;
|
||||
super->return_msg = dns_copy_msg(qstate->return_msg, super->region);
|
||||
if(!super->return_msg) {
|
||||
log_err("subnetcache: copy response, out of memory");
|
||||
super->return_rcode = LDNS_RCODE_SERVFAIL;
|
||||
}
|
||||
}
|
||||
|
||||
size_t
|
||||
|
||||
@@ -69,8 +69,18 @@ struct subnet_env {
|
||||
};
|
||||
|
||||
struct subnet_msg_cache_data {
|
||||
/** Tree for nodes with IPv4 subnets. */
|
||||
struct addrtree* tree4;
|
||||
/** Tree for nodes with IPv6 subnets. */
|
||||
struct addrtree* tree6;
|
||||
/** If servfail is stored, for how long. Abs time in seconds.
|
||||
* This protects against too much recusion on the item when
|
||||
* resolution fails, for a couple of seconds. */
|
||||
time_t ttl_servfail;
|
||||
/** servfail ede */
|
||||
sldns_ede_code ede_fail;
|
||||
/** servfail reason */
|
||||
char* reason_fail;
|
||||
};
|
||||
|
||||
struct subnet_qstate {
|
||||
@@ -102,6 +112,14 @@ struct subnet_qstate {
|
||||
int started_no_cache_store;
|
||||
/** has the subnet module been started with no_cache_lookup? */
|
||||
int started_no_cache_lookup;
|
||||
/** Wait for subquery that has been started for nonsubnet lookup. */
|
||||
int wait_subquery;
|
||||
/** The subquery waited for is done. */
|
||||
int wait_subquery_done;
|
||||
/** The subnet state is a subquery state for nonsubnet lookup. */
|
||||
int is_subquery_nonsubnet;
|
||||
/** This is a subquery, and it is made due to a scope zero request. */
|
||||
int is_subquery_scopezero;
|
||||
};
|
||||
|
||||
void subnet_data_delete(void* d, void* ATTR_UNUSED(arg));
|
||||
|
||||
@@ -100,6 +100,8 @@ ipsecmod_whitelist_apply_cfg(struct ipsecmod_env* ie,
|
||||
struct config_file* cfg)
|
||||
{
|
||||
ie->whitelist = rbtree_create(name_tree_compare);
|
||||
if (!ie->whitelist)
|
||||
return 0;
|
||||
if(!read_whitelist(ie->whitelist, cfg))
|
||||
return 0;
|
||||
name_tree_init_parents(ie->whitelist);
|
||||
|
||||
+92
-38
@@ -51,18 +51,28 @@
|
||||
#include "util/config_file.h"
|
||||
#include "services/cache/dns.h"
|
||||
#include "sldns/wire2str.h"
|
||||
#ifdef HAVE_SYS_WAIT_H
|
||||
#include <sys/wait.h>
|
||||
#endif
|
||||
|
||||
/** Apply configuration to ipsecmod module 'global' state. */
|
||||
static int
|
||||
ipsecmod_apply_cfg(struct ipsecmod_env* ipsecmod_env, struct config_file* cfg)
|
||||
{
|
||||
if(cfg->ipsecmod_whitelist &&
|
||||
!ipsecmod_whitelist_apply_cfg(ipsecmod_env, cfg))
|
||||
return 0;
|
||||
if(!cfg->ipsecmod_enabled)
|
||||
return 1;
|
||||
if(!cfg->ipsecmod_hook || (cfg->ipsecmod_hook && !cfg->ipsecmod_hook[0])) {
|
||||
log_err("ipsecmod: missing ipsecmod-hook.");
|
||||
return 0;
|
||||
}
|
||||
if(cfg->ipsecmod_whitelist &&
|
||||
!ipsecmod_whitelist_apply_cfg(ipsecmod_env, cfg))
|
||||
if(access(cfg->ipsecmod_hook, X_OK) != 0) {
|
||||
log_err("ipsecmod: ipsecmod-hook '%s' is not an executable file: %s",
|
||||
cfg->ipsecmod_hook, strerror(errno));
|
||||
return 0;
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
@@ -163,7 +173,7 @@ generate_request(struct module_qstate* qstate, int id, uint8_t* name,
|
||||
}
|
||||
|
||||
fptr_ok(fptr_whitelist_modenv_attach_sub(qstate->env->attach_sub));
|
||||
if(!(*qstate->env->attach_sub)(qstate, &ask,
|
||||
if(!(*qstate->env->attach_sub)(qstate, &ask, NULL,
|
||||
(uint16_t)(BIT_RD|flags), 0, 0, &newq)){
|
||||
log_err("Could not generate request: out of memory");
|
||||
return 0;
|
||||
@@ -250,27 +260,16 @@ call_hook(struct module_qstate* qstate, struct ipsecmod_qstate* iq,
|
||||
struct ipsecmod_env* ATTR_UNUSED(ie))
|
||||
{
|
||||
size_t slen, tempdata_len, tempstring_len, i;
|
||||
char str[65535], *s, *tempstring;
|
||||
char qname_s[LDNS_MAX_DOMAINLEN*5+16], ttl_s[32], a_s[32768], k_s[32768];
|
||||
char *s, *tempstring;
|
||||
int w = 0, w_temp, qtype;
|
||||
struct ub_packed_rrset_key* rrset_key;
|
||||
struct packed_rrset_data* rrset_data;
|
||||
uint8_t *tempdata;
|
||||
pid_t pid;
|
||||
int st;
|
||||
char* argv[6];
|
||||
|
||||
/* Check if a shell is available */
|
||||
if(system(NULL) == 0) {
|
||||
log_err("ipsecmod: no shell available for ipsecmod-hook");
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Zero the buffer. */
|
||||
s = str;
|
||||
slen = sizeof(str);
|
||||
memset(s, 0, slen);
|
||||
|
||||
/* Copy the hook into the buffer. */
|
||||
w += sldns_str_print(&s, &slen, "%s", qstate->env->cfg->ipsecmod_hook);
|
||||
/* Put space into the buffer. */
|
||||
w += sldns_str_print(&s, &slen, " ");
|
||||
/* Copy the qname into the buffer. */
|
||||
tempstring = sldns_wire2str_dname(qstate->qinfo.qname,
|
||||
qstate->qinfo.qname_len);
|
||||
@@ -283,17 +282,24 @@ call_hook(struct module_qstate* qstate, struct ipsecmod_qstate* iq,
|
||||
free(tempstring);
|
||||
return 0;
|
||||
}
|
||||
w += sldns_str_print(&s, &slen, "\"%s\"", tempstring);
|
||||
if(strlen(tempstring)+1 > sizeof(qname_s)) {
|
||||
log_err("ipsecmod: string too long");
|
||||
free(tempstring);
|
||||
return 0;
|
||||
}
|
||||
snprintf(qname_s, sizeof(qname_s), "%s", tempstring);
|
||||
free(tempstring);
|
||||
/* Put space into the buffer. */
|
||||
w += sldns_str_print(&s, &slen, " ");
|
||||
|
||||
/* Copy the IPSECKEY TTL into the buffer. */
|
||||
rrset_data = (struct packed_rrset_data*)iq->ipseckey_rrset->entry.data;
|
||||
w += sldns_str_print(&s, &slen, "\"%ld\"", (long)rrset_data->ttl);
|
||||
/* Put space into the buffer. */
|
||||
w += sldns_str_print(&s, &slen, " ");
|
||||
snprintf(ttl_s, sizeof(ttl_s), "%ld", (long)rrset_data->ttl);
|
||||
|
||||
rrset_key = reply_find_answer_rrset(&qstate->return_msg->qinfo,
|
||||
qstate->return_msg->rep);
|
||||
if(!rrset_key) {
|
||||
log_err("ipsecmod: could not find answer rrset for A/AAAA");
|
||||
return 0;
|
||||
}
|
||||
/* Double check that the records are indeed A/AAAA.
|
||||
* This should never happen as this function is only executed for A/AAAA
|
||||
* queries but make sure we don't pass anything other than A/AAAA to the
|
||||
@@ -304,9 +310,15 @@ call_hook(struct module_qstate* qstate, struct ipsecmod_qstate* iq,
|
||||
return 0;
|
||||
}
|
||||
rrset_data = (struct packed_rrset_data*)rrset_key->entry.data;
|
||||
/* Copy the A/AAAA record(s) into the buffer. Start and end this section
|
||||
* with a double quote. */
|
||||
w += sldns_str_print(&s, &slen, "\"");
|
||||
if(!rrset_data) {
|
||||
log_err("ipsecmod: Answer has no data");
|
||||
return 0;
|
||||
}
|
||||
/* Copy the A/AAAA record(s) into the buffer. */
|
||||
w = 0;
|
||||
s = a_s;
|
||||
slen = sizeof(a_s);
|
||||
memset(s, 0, slen);
|
||||
for(i=0; i<rrset_data->count; i++) {
|
||||
if(i > 0) {
|
||||
/* Put space into the buffer. */
|
||||
@@ -322,7 +334,7 @@ call_hook(struct module_qstate* qstate, struct ipsecmod_qstate* iq,
|
||||
} else if((size_t)w_temp >= slen) {
|
||||
s = NULL; /* We do not want str to point outside of buffer. */
|
||||
slen = 0;
|
||||
log_err("ipsecmod: shell command too long");
|
||||
log_err("ipsecmod: command addr argument too long");
|
||||
return 0;
|
||||
} else {
|
||||
s += w_temp;
|
||||
@@ -330,12 +342,17 @@ call_hook(struct module_qstate* qstate, struct ipsecmod_qstate* iq,
|
||||
w += w_temp;
|
||||
}
|
||||
}
|
||||
w += sldns_str_print(&s, &slen, "\"");
|
||||
/* Put space into the buffer. */
|
||||
w += sldns_str_print(&s, &slen, " ");
|
||||
if(w >= (int)sizeof(a_s)) {
|
||||
log_err("ipsecmod: command addr argument too long");
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Copy the IPSECKEY record(s) into the buffer. Start and end this section
|
||||
* with a double quote. */
|
||||
w += sldns_str_print(&s, &slen, "\"");
|
||||
w = 0;
|
||||
s = k_s;
|
||||
slen = sizeof(k_s);
|
||||
memset(s, 0, slen);
|
||||
rrset_data = (struct packed_rrset_data*)iq->ipseckey_rrset->entry.data;
|
||||
for(i=0; i<rrset_data->count; i++) {
|
||||
if(i > 0) {
|
||||
@@ -362,15 +379,44 @@ call_hook(struct module_qstate* qstate, struct ipsecmod_qstate* iq,
|
||||
w += w_temp;
|
||||
}
|
||||
}
|
||||
w += sldns_str_print(&s, &slen, "\"");
|
||||
if(w >= (int)sizeof(str)) {
|
||||
log_err("ipsecmod: shell command too long");
|
||||
if(w >= (int)sizeof(k_s)) {
|
||||
log_err("ipsecmod: command ipseckey argument too long");
|
||||
return 0;
|
||||
}
|
||||
verbose(VERB_ALGO, "ipsecmod: shell command: '%s'", str);
|
||||
|
||||
/* ipsecmod-hook should return 0 on success. */
|
||||
if(system(str) != 0)
|
||||
/* exec the ipsecmod-hook */
|
||||
argv[0] = qstate->env->cfg->ipsecmod_hook;
|
||||
argv[1] = qname_s;
|
||||
argv[2] = ttl_s;
|
||||
argv[3] = a_s;
|
||||
argv[4] = k_s;
|
||||
argv[5] = NULL;
|
||||
verbose(VERB_ALGO, "ipsecmod: exec %s \"%s\" %s \"%s\" \"%s\"",
|
||||
argv[0], argv[1], argv[2], argv[3], argv[4]);
|
||||
if((pid = fork()) < 0) {
|
||||
log_err("ipsecmod: for exec, can not fork: %s",
|
||||
strerror(errno));
|
||||
return 0;
|
||||
}
|
||||
if(pid == 0) {
|
||||
if(execv(argv[0], argv) < 0)
|
||||
fprintf(stderr, "ipsecmod: execv: %s\n",
|
||||
strerror(errno));
|
||||
_exit(127);
|
||||
}
|
||||
while(1) {
|
||||
if(waitpid(pid, &st, 0) < 0) {
|
||||
if(errno == EINTR)
|
||||
continue;
|
||||
log_err("ipsecmod: wait_pid: %s", strerror(errno));
|
||||
}
|
||||
break;
|
||||
}
|
||||
if(!(WIFEXITED(st) && WEXITSTATUS(st) == 0)) {
|
||||
/* the command failed */
|
||||
return 0;
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
@@ -435,6 +481,12 @@ ipsecmod_handle_query(struct module_qstate* qstate,
|
||||
* ipsecmod_max_ttl. */
|
||||
rrset_key = reply_find_answer_rrset(&qstate->return_msg->qinfo,
|
||||
qstate->return_msg->rep);
|
||||
if(!rrset_key) {
|
||||
log_err("ipsecmod: reply-find-answer failed");
|
||||
errinf(qstate, "ipsecmod: reply-find-answer failed");
|
||||
ipsecmod_error(qstate, id);
|
||||
return;
|
||||
}
|
||||
rrset_data = (struct packed_rrset_data*)rrset_key->entry.data;
|
||||
if(rrset_data->ttl > (time_t)qstate->env->cfg->ipsecmod_max_ttl) {
|
||||
/* Update TTL for rrset to fixed value. */
|
||||
@@ -576,6 +628,8 @@ ipsecmod_inform_super(struct module_qstate* qstate, int id,
|
||||
verbose(VERB_ALGO, "super has no ipsecmod state");
|
||||
return;
|
||||
}
|
||||
if(!siq->enabled)
|
||||
return;
|
||||
|
||||
if(qstate->return_msg) {
|
||||
struct ub_packed_rrset_key* rrset_key = reply_find_answer_rrset(
|
||||
|
||||
+17
-14
@@ -143,7 +143,7 @@ static int add_to_ipset(filter_dev dev, const char *setname, const void *ipaddr,
|
||||
struct nlmsghdr *nlh;
|
||||
struct nfgenmsg *nfg;
|
||||
struct nlattr *nested[2];
|
||||
static char buffer[BUFF_LEN];
|
||||
char buffer[BUFF_LEN];
|
||||
|
||||
if (strlen(setname) >= IPSET_MAXNAMELEN) {
|
||||
errno = ENAMETOOLONG;
|
||||
@@ -208,13 +208,6 @@ ipset_add_rrset_data(struct ipset_env *ie,
|
||||
ret = add_to_ipset((filter_dev)ie->dev, setname, rr_data + 2, af);
|
||||
if (ret < 0) {
|
||||
log_err("ipset: could not add %s into %s", dname, setname);
|
||||
|
||||
#if HAVE_NET_PFVAR_H
|
||||
/* don't close as we might not be able to open again due to dropped privs */
|
||||
#else
|
||||
mnl_socket_close((filter_dev)ie->dev);
|
||||
ie->dev = NULL;
|
||||
#endif
|
||||
break;
|
||||
}
|
||||
}
|
||||
@@ -226,15 +219,15 @@ ipset_check_zones_for_rrset(struct module_env *env, struct ipset_env *ie,
|
||||
struct ub_packed_rrset_key *rrset, const char *qname, int qlen,
|
||||
const char *setname, int af)
|
||||
{
|
||||
static char dname[BUFF_LEN];
|
||||
char dname[LDNS_MAX_DOMAINLEN*4+16];
|
||||
const char *ds, *qs;
|
||||
int dlen, plen;
|
||||
|
||||
struct config_strlist *p;
|
||||
struct packed_rrset_data *d;
|
||||
|
||||
dlen = sldns_wire2str_dname_buf(rrset->rk.dname, rrset->rk.dname_len, dname, BUFF_LEN);
|
||||
if (dlen == 0) {
|
||||
dlen = sldns_wire2str_dname_buf(rrset->rk.dname, rrset->rk.dname_len, dname, sizeof(dname));
|
||||
if (dlen == 0 || dlen >= (int)sizeof(dname)) {
|
||||
log_err("bad domain name");
|
||||
return -1;
|
||||
}
|
||||
@@ -276,7 +269,7 @@ static int ipset_update(struct module_env *env, struct dns_msg *return_msg,
|
||||
const char *setname;
|
||||
struct ub_packed_rrset_key *rrset;
|
||||
int af;
|
||||
static char qname[BUFF_LEN];
|
||||
char qname[LDNS_MAX_DOMAINLEN*4+16];
|
||||
int qlen;
|
||||
|
||||
#ifdef HAVE_NET_PFVAR_H
|
||||
@@ -292,8 +285,8 @@ static int ipset_update(struct module_env *env, struct dns_msg *return_msg,
|
||||
#endif
|
||||
|
||||
qlen = sldns_wire2str_dname_buf(qinfo.qname, qinfo.qname_len,
|
||||
qname, BUFF_LEN);
|
||||
if(qlen == 0) {
|
||||
qname, sizeof(qname));
|
||||
if(qlen == 0 || qlen >= (int)sizeof(qname)) {
|
||||
log_err("bad domain name");
|
||||
return -1;
|
||||
}
|
||||
@@ -372,6 +365,16 @@ int ipset_init(struct module_env* env, int id) {
|
||||
|
||||
ipset_env->name_v4 = env->cfg->ipset_name_v4;
|
||||
ipset_env->name_v6 = env->cfg->ipset_name_v6;
|
||||
#ifndef HAVE_NET_PFVAR_H
|
||||
if (ipset_env->name_v4 && strlen(ipset_env->name_v4) >= IPSET_MAXNAMELEN) {
|
||||
log_err("ipset: name-v4 exceeds IPSET_MAXNAMELEN (%d)", IPSET_MAXNAMELEN);
|
||||
return 0;
|
||||
}
|
||||
if (ipset_env->name_v6 && strlen(ipset_env->name_v6) >= IPSET_MAXNAMELEN) {
|
||||
log_err("ipset: name-v6 exceeds IPSET_MAXNAMELEN (%d)", IPSET_MAXNAMELEN);
|
||||
return 0;
|
||||
}
|
||||
#endif
|
||||
|
||||
ipset_env->v4_enabled = !ipset_env->name_v4 || (strlen(ipset_env->name_v4) == 0) ? 0 : 1;
|
||||
ipset_env->v6_enabled = !ipset_env->name_v6 || (strlen(ipset_env->name_v6) == 0) ? 0 : 1;
|
||||
|
||||
+31
-24
@@ -118,10 +118,10 @@ delegpt_add_ns(struct delegpt* dp, struct regional* region, uint8_t* name,
|
||||
sizeof(struct delegpt_ns));
|
||||
if(!ns)
|
||||
return 0;
|
||||
ns->next = dp->nslist;
|
||||
ns->namelen = len;
|
||||
dp->nslist = ns;
|
||||
ns->name = regional_alloc_init(region, name, ns->namelen);
|
||||
if(!ns->name)
|
||||
return 0;
|
||||
ns->cache_lookup_count = 0;
|
||||
ns->resolved = 0;
|
||||
ns->got4 = 0;
|
||||
@@ -137,7 +137,9 @@ delegpt_add_ns(struct delegpt* dp, struct regional* region, uint8_t* name,
|
||||
} else {
|
||||
ns->tls_auth_name = NULL;
|
||||
}
|
||||
return ns->name != 0;
|
||||
ns->next = dp->nslist;
|
||||
dp->nslist = ns;
|
||||
return 1;
|
||||
}
|
||||
|
||||
struct delegpt_ns*
|
||||
@@ -223,11 +225,7 @@ delegpt_add_addr(struct delegpt* dp, struct regional* region,
|
||||
sizeof(struct delegpt_addr));
|
||||
if(!a)
|
||||
return 0;
|
||||
a->next_target = dp->target_list;
|
||||
dp->target_list = a;
|
||||
a->next_result = 0;
|
||||
a->next_usable = dp->usable_list;
|
||||
dp->usable_list = a;
|
||||
memcpy(&a->addr, addr, addrlen);
|
||||
a->addrlen = addrlen;
|
||||
a->attempts = 0;
|
||||
@@ -241,6 +239,10 @@ delegpt_add_addr(struct delegpt* dp, struct regional* region,
|
||||
} else {
|
||||
a->tls_auth_name = NULL;
|
||||
}
|
||||
a->next_target = dp->target_list;
|
||||
dp->target_list = a;
|
||||
a->next_usable = dp->usable_list;
|
||||
dp->usable_list = a;
|
||||
return 1;
|
||||
}
|
||||
|
||||
@@ -398,30 +400,33 @@ delegpt_count_missing_targets(struct delegpt* dp, int* alllame)
|
||||
|
||||
/** find NS rrset in given list */
|
||||
static struct ub_packed_rrset_key*
|
||||
find_NS(struct reply_info* rep, size_t from, size_t to)
|
||||
find_NS(struct reply_info* rep, size_t from, size_t to, uint16_t qclass)
|
||||
{
|
||||
size_t i;
|
||||
for(i=from; i<to; i++) {
|
||||
if(ntohs(rep->rrsets[i]->rk.type) == LDNS_RR_TYPE_NS)
|
||||
if(ntohs(rep->rrsets[i]->rk.type) == LDNS_RR_TYPE_NS &&
|
||||
ntohs(rep->rrsets[i]->rk.rrset_class) == qclass)
|
||||
return rep->rrsets[i];
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
struct delegpt*
|
||||
delegpt_from_message(struct dns_msg* msg, struct regional* region)
|
||||
delegpt_from_message(struct dns_msg* msg, struct regional* region, int port)
|
||||
{
|
||||
struct ub_packed_rrset_key* ns_rrset = NULL;
|
||||
struct delegpt* dp;
|
||||
size_t i;
|
||||
/* look for NS records in the authority section... */
|
||||
ns_rrset = find_NS(msg->rep, msg->rep->an_numrrsets,
|
||||
msg->rep->an_numrrsets+msg->rep->ns_numrrsets);
|
||||
msg->rep->an_numrrsets+msg->rep->ns_numrrsets,
|
||||
msg->qinfo.qclass);
|
||||
|
||||
/* In some cases (even legitimate, perfectly legal cases), the
|
||||
* NS set for the "referral" might be in the answer section. */
|
||||
if(!ns_rrset)
|
||||
ns_rrset = find_NS(msg->rep, 0, msg->rep->an_numrrsets);
|
||||
ns_rrset = find_NS(msg->rep, 0, msg->rep->an_numrrsets,
|
||||
msg->qinfo.qclass);
|
||||
|
||||
/* If there was no NS rrset in the authority section, then this
|
||||
* wasn't a referral message. (It might not actually be a
|
||||
@@ -436,7 +441,7 @@ delegpt_from_message(struct dns_msg* msg, struct regional* region)
|
||||
dp->has_parent_side_NS = 1; /* created from message */
|
||||
if(!delegpt_set_name(dp, region, ns_rrset->rk.dname))
|
||||
return NULL;
|
||||
if(!delegpt_rrset_add_ns(dp, region, ns_rrset, 0))
|
||||
if(!delegpt_rrset_add_ns(dp, region, ns_rrset, 0, port))
|
||||
return NULL;
|
||||
|
||||
/* add glue, A and AAAA in answer and additional section */
|
||||
@@ -447,10 +452,12 @@ delegpt_from_message(struct dns_msg* msg, struct regional* region)
|
||||
i < (msg->rep->an_numrrsets+msg->rep->ns_numrrsets))
|
||||
continue;
|
||||
|
||||
if(ntohs(s->rk.type) == LDNS_RR_TYPE_A) {
|
||||
if(ntohs(s->rk.type) == LDNS_RR_TYPE_A &&
|
||||
ntohs(s->rk.rrset_class) == msg->qinfo.qclass) {
|
||||
if(!delegpt_add_rrset_A(dp, region, s, 0, NULL))
|
||||
return NULL;
|
||||
} else if(ntohs(s->rk.type) == LDNS_RR_TYPE_AAAA) {
|
||||
} else if(ntohs(s->rk.type) == LDNS_RR_TYPE_AAAA &&
|
||||
ntohs(s->rk.rrset_class) == msg->qinfo.qclass) {
|
||||
if(!delegpt_add_rrset_AAAA(dp, region, s, 0, NULL))
|
||||
return NULL;
|
||||
}
|
||||
@@ -460,7 +467,7 @@ delegpt_from_message(struct dns_msg* msg, struct regional* region)
|
||||
|
||||
int
|
||||
delegpt_rrset_add_ns(struct delegpt* dp, struct regional* region,
|
||||
struct ub_packed_rrset_key* ns_rrset, uint8_t lame)
|
||||
struct ub_packed_rrset_key* ns_rrset, uint8_t lame, int port)
|
||||
{
|
||||
struct packed_rrset_data* nsdata = (struct packed_rrset_data*)
|
||||
ns_rrset->entry.data;
|
||||
@@ -475,7 +482,7 @@ delegpt_rrset_add_ns(struct delegpt* dp, struct regional* region,
|
||||
continue; /* bad format */
|
||||
/* add rdata of NS (= wirefmt dname), skip rdatalen bytes */
|
||||
if(!delegpt_add_ns(dp, region, nsdata->rr_data[i]+2, lame,
|
||||
NULL, UNBOUND_DNS_PORT))
|
||||
NULL, (port==-1?UNBOUND_DNS_PORT:port)))
|
||||
return 0;
|
||||
}
|
||||
return 1;
|
||||
@@ -534,7 +541,7 @@ delegpt_add_rrset(struct delegpt* dp, struct regional* region,
|
||||
if(!rrset)
|
||||
return 1;
|
||||
if(ntohs(rrset->rk.type) == LDNS_RR_TYPE_NS)
|
||||
return delegpt_rrset_add_ns(dp, region, rrset, lame);
|
||||
return delegpt_rrset_add_ns(dp, region, rrset, lame, -1);
|
||||
else if(ntohs(rrset->rk.type) == LDNS_RR_TYPE_A)
|
||||
return delegpt_add_rrset_A(dp, region, rrset, lame, additions);
|
||||
else if(ntohs(rrset->rk.type) == LDNS_RR_TYPE_AAAA)
|
||||
@@ -659,8 +666,6 @@ int delegpt_add_ns_mlc(struct delegpt* dp, uint8_t* name, uint8_t lame,
|
||||
free(ns);
|
||||
return 0;
|
||||
}
|
||||
ns->next = dp->nslist;
|
||||
dp->nslist = ns;
|
||||
ns->cache_lookup_count = 0;
|
||||
ns->resolved = 0;
|
||||
ns->got4 = 0;
|
||||
@@ -679,6 +684,8 @@ int delegpt_add_ns_mlc(struct delegpt* dp, uint8_t* name, uint8_t lame,
|
||||
} else {
|
||||
ns->tls_auth_name = NULL;
|
||||
}
|
||||
ns->next = dp->nslist;
|
||||
dp->nslist = ns;
|
||||
return 1;
|
||||
}
|
||||
|
||||
@@ -704,11 +711,7 @@ int delegpt_add_addr_mlc(struct delegpt* dp, struct sockaddr_storage* addr,
|
||||
a = (struct delegpt_addr*)malloc(sizeof(struct delegpt_addr));
|
||||
if(!a)
|
||||
return 0;
|
||||
a->next_target = dp->target_list;
|
||||
dp->target_list = a;
|
||||
a->next_result = 0;
|
||||
a->next_usable = dp->usable_list;
|
||||
dp->usable_list = a;
|
||||
memcpy(&a->addr, addr, addrlen);
|
||||
a->addrlen = addrlen;
|
||||
a->attempts = 0;
|
||||
@@ -724,6 +727,10 @@ int delegpt_add_addr_mlc(struct delegpt* dp, struct sockaddr_storage* addr,
|
||||
} else {
|
||||
a->tls_auth_name = NULL;
|
||||
}
|
||||
a->next_target = dp->target_list;
|
||||
dp->target_list = a;
|
||||
a->next_usable = dp->usable_list;
|
||||
dp->usable_list = a;
|
||||
return 1;
|
||||
}
|
||||
|
||||
|
||||
+14
-2
@@ -79,6 +79,16 @@ struct delegpt {
|
||||
* Also true if the delegationpoint was created from a delegation
|
||||
* message and thus contains the parent-side-info already. */
|
||||
uint8_t has_parent_side_NS;
|
||||
/** if true, the delegation point has reached last resort processing
|
||||
* and the parent side information has been possibly added to the
|
||||
* delegation point.
|
||||
* For now this signals that further target lookups will ignore
|
||||
* the configured target-fetch-policy and only resolve on
|
||||
* demand to try and avoid triggering limits at this stage (.i.e, it
|
||||
* is very likely that the A/AAAA queries for the newly added name
|
||||
* servers will not yield new IP addresses and trigger NXNS
|
||||
* countermeasures. */
|
||||
uint8_t fallback_to_parent_side_NS;
|
||||
/** for assertions on type of delegpt */
|
||||
uint8_t dp_type_mlc;
|
||||
/** use SSL for upstream query */
|
||||
@@ -211,10 +221,11 @@ int delegpt_add_ns(struct delegpt* dp, struct regional* regional,
|
||||
* @param regional: where to allocate the info.
|
||||
* @param ns_rrset: NS rrset.
|
||||
* @param lame: rrset is lame, disprefer it.
|
||||
* @param port: port or -1 if not set.
|
||||
* @return 0 on alloc error.
|
||||
*/
|
||||
int delegpt_rrset_add_ns(struct delegpt* dp, struct regional* regional,
|
||||
struct ub_packed_rrset_key* ns_rrset, uint8_t lame);
|
||||
struct ub_packed_rrset_key* ns_rrset, uint8_t lame, int port);
|
||||
|
||||
/**
|
||||
* Add target address to the delegation point.
|
||||
@@ -355,11 +366,12 @@ size_t delegpt_count_targets(struct delegpt* dp);
|
||||
*
|
||||
* @param msg: the dns message, referral.
|
||||
* @param regional: where to allocate delegation point.
|
||||
* @param port: if not -1 specifies a port number.
|
||||
* @return new delegation point or NULL on alloc error, or if the
|
||||
* message was not appropriate.
|
||||
*/
|
||||
struct delegpt* delegpt_from_message(struct dns_msg* msg,
|
||||
struct regional* regional);
|
||||
struct regional* regional, int port);
|
||||
|
||||
/**
|
||||
* Mark negative return in delegation point for specific nameserver.
|
||||
|
||||
@@ -132,6 +132,18 @@ donotq_apply_cfg(struct iter_donotq* dq, struct config_file* cfg)
|
||||
if(cfg->do_ip6) {
|
||||
if(!donotq_str_cfg(dq, "::1"))
|
||||
return 0;
|
||||
if(!donotq_str_cfg(dq, "::ffff:127.0.0.0/104"))
|
||||
return 0;
|
||||
}
|
||||
/* RFC 1122 3.2.1.3 / RFC 6890 / RFC 4291 2.5.2: not valid as
|
||||
* destination; on Linux these route to the local host. */
|
||||
if(!donotq_str_cfg(dq, "0.0.0.0/8"))
|
||||
return 0;
|
||||
if(cfg->do_ip6) {
|
||||
if(!donotq_str_cfg(dq, "::"))
|
||||
return 0;
|
||||
if(!donotq_str_cfg(dq, "::ffff:0:0/96"))
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
addr_tree_init_parents(&dq->tree);
|
||||
|
||||
+26
-11
@@ -139,6 +139,17 @@ forwards_insert_data(struct iter_forwards* fwd, uint16_t c, uint8_t* nm,
|
||||
return 1;
|
||||
}
|
||||
|
||||
static struct iter_forward_zone*
|
||||
fwd_zone_find(struct iter_forwards* fwd, uint16_t c, uint8_t* nm)
|
||||
{
|
||||
struct iter_forward_zone key;
|
||||
key.node.key = &key;
|
||||
key.dclass = c;
|
||||
key.name = nm;
|
||||
key.namelabs = dname_count_size_labels(nm, &key.namelen);
|
||||
return (struct iter_forward_zone*)rbtree_search(fwd->tree, &key);
|
||||
}
|
||||
|
||||
/** insert new info into forward structure given dp */
|
||||
static int
|
||||
forwards_insert(struct iter_forwards* fwd, uint16_t c, struct delegpt* dp)
|
||||
@@ -217,6 +228,11 @@ read_fwds_host(struct config_stub* s, struct delegpt* dp)
|
||||
s->name, p->str);
|
||||
return 0;
|
||||
}
|
||||
if(dname_subdomain_c(dname, dp->name)) {
|
||||
log_warn("forward-host '%s' may have a circular "
|
||||
"dependency on forward-zone '%s'",
|
||||
p->str, s->name);
|
||||
}
|
||||
#if ! defined(HAVE_SSL_SET1_HOST) && ! defined(HAVE_X509_VERIFY_PARAM_SET1_HOST)
|
||||
if(tls_auth_name)
|
||||
log_err("no name verification functionality in "
|
||||
@@ -321,6 +337,11 @@ make_stub_holes(struct iter_forwards* fwd, struct config_file* cfg)
|
||||
log_err("cannot parse stub name '%s'", s->name);
|
||||
return 0;
|
||||
}
|
||||
if(fwd_zone_find(fwd, LDNS_RR_CLASS_IN, dname) != NULL) {
|
||||
/* Already a forward zone there. */
|
||||
free(dname);
|
||||
continue;
|
||||
}
|
||||
if(!fwd_add_stub_hole(fwd, LDNS_RR_CLASS_IN, dname)) {
|
||||
free(dname);
|
||||
log_err("out of memory");
|
||||
@@ -345,6 +366,11 @@ make_auth_holes(struct iter_forwards* fwd, struct config_file* cfg)
|
||||
log_err("cannot parse auth name '%s'", a->name);
|
||||
return 0;
|
||||
}
|
||||
if(fwd_zone_find(fwd, LDNS_RR_CLASS_IN, dname) != NULL) {
|
||||
/* Already a forward zone there. */
|
||||
free(dname);
|
||||
continue;
|
||||
}
|
||||
if(!fwd_add_stub_hole(fwd, LDNS_RR_CLASS_IN, dname)) {
|
||||
free(dname);
|
||||
log_err("out of memory");
|
||||
@@ -537,17 +563,6 @@ forwards_get_mem(struct iter_forwards* fwd)
|
||||
return s;
|
||||
}
|
||||
|
||||
static struct iter_forward_zone*
|
||||
fwd_zone_find(struct iter_forwards* fwd, uint16_t c, uint8_t* nm)
|
||||
{
|
||||
struct iter_forward_zone key;
|
||||
key.node.key = &key;
|
||||
key.dclass = c;
|
||||
key.name = nm;
|
||||
key.namelabs = dname_count_size_labels(nm, &key.namelen);
|
||||
return (struct iter_forward_zone*)rbtree_search(fwd->tree, &key);
|
||||
}
|
||||
|
||||
int
|
||||
forwards_add_zone(struct iter_forwards* fwd, uint16_t c, struct delegpt* dp,
|
||||
int nolock)
|
||||
|
||||
@@ -231,6 +231,11 @@ read_stubs_host(struct config_stub* s, struct delegpt* dp)
|
||||
s->name, p->str);
|
||||
return 0;
|
||||
}
|
||||
if(dname_subdomain_c(dname, dp->name)) {
|
||||
log_warn("stub-host '%s' may have a circular "
|
||||
"dependency on stub-zone '%s'",
|
||||
p->str, s->name);
|
||||
}
|
||||
#if ! defined(HAVE_SSL_SET1_HOST) && ! defined(HAVE_X509_VERIFY_PARAM_SET1_HOST)
|
||||
if(tls_auth_name)
|
||||
log_err("no name verification functionality in "
|
||||
|
||||
+167
-1
@@ -207,6 +207,168 @@ size_t priv_get_mem(struct iter_priv* priv)
|
||||
return sizeof(*priv) + regional_get_mem(priv->region);
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if svcparam ipv4hint contains a private address.
|
||||
* @param priv: private address lookup struct.
|
||||
* @param d: the data bytes.
|
||||
* @param data_len: number of data bytes in the svcparam.
|
||||
* @param addr: address to return the private address to log in to.
|
||||
* It has space for IPv4 and IPv6 addresses.
|
||||
* @param addrlen: length of the addr. Returns the correct size for the addr.
|
||||
* @return true if the rdata contains a private address.
|
||||
*/
|
||||
static int svcb_ipv4hint_contains_priv_addr(struct iter_priv* priv,
|
||||
uint8_t* d, uint16_t data_len, struct sockaddr_storage* addr,
|
||||
socklen_t* addrlen)
|
||||
{
|
||||
struct sockaddr_in sa;
|
||||
*addrlen = (socklen_t)sizeof(struct sockaddr_in);
|
||||
memset(&sa, 0, sizeof(struct sockaddr_in));
|
||||
sa.sin_family = AF_INET;
|
||||
sa.sin_port = (in_port_t)htons(UNBOUND_DNS_PORT);
|
||||
|
||||
while(data_len >= LDNS_IP4ADDRLEN) {
|
||||
memmove(&sa.sin_addr, d, LDNS_IP4ADDRLEN);
|
||||
memmove(addr, &sa, *addrlen);
|
||||
if(priv_lookup_addr(priv, addr, *addrlen))
|
||||
return 1;
|
||||
|
||||
d += LDNS_IP4ADDRLEN;
|
||||
data_len -= LDNS_IP4ADDRLEN;
|
||||
}
|
||||
/* if data_len != 0 here, then the svcparam is malformed. */
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if svcparam ipv6hint contains a private address.
|
||||
* @param priv: private address lookup struct.
|
||||
* @param d: the data bytes.
|
||||
* @param data_len: number of data bytes in the svcparam.
|
||||
* @param addr: address to return the private address to log in to.
|
||||
* It has space for IPv4 and IPv6 addresses.
|
||||
* @param addrlen: length of the addr. Returns the correct size for the addr.
|
||||
* @return true if the rdata contains a private address.
|
||||
*/
|
||||
static int svcb_ipv6hint_contains_priv_addr(struct iter_priv* priv,
|
||||
uint8_t* d, uint16_t data_len, struct sockaddr_storage* addr,
|
||||
socklen_t* addrlen)
|
||||
{
|
||||
struct sockaddr_in6 sa;
|
||||
*addrlen = (socklen_t)sizeof(struct sockaddr_in6);
|
||||
memset(&sa, 0, sizeof(struct sockaddr_in6));
|
||||
sa.sin6_family = AF_INET6;
|
||||
sa.sin6_port = (in_port_t)htons(UNBOUND_DNS_PORT);
|
||||
|
||||
while(data_len >= LDNS_IP6ADDRLEN) {
|
||||
memmove(&sa.sin6_addr, d, LDNS_IP6ADDRLEN);
|
||||
memmove(addr, &sa, *addrlen);
|
||||
if(priv_lookup_addr(priv, addr, *addrlen))
|
||||
return 1;
|
||||
|
||||
d += LDNS_IP6ADDRLEN;
|
||||
data_len -= LDNS_IP6ADDRLEN;
|
||||
}
|
||||
/* if data_len != 0 here, then the svcparam is malformed. */
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if type SVCB and HTTPS rdata contains a private address.
|
||||
* @param priv: private address lookup struct.
|
||||
* @param pkt: the packet.
|
||||
* @param rr: the rr with rdata to check.
|
||||
* @param addr: address to return the private address to log in to.
|
||||
* @param addrlen: length of the addr. Initially the total size, on
|
||||
* return the correct size for the addr.
|
||||
* @return true if the rdata contains a private address.
|
||||
*/
|
||||
static int svcb_rr_contains_priv_addr(struct iter_priv* priv,
|
||||
sldns_buffer* pkt, struct rr_parse* rr, struct sockaddr_storage* addr,
|
||||
socklen_t* addrlen)
|
||||
{
|
||||
uint8_t* d = rr->ttl_data;
|
||||
uint16_t svcparamkey, data_len, rdatalen;
|
||||
size_t oldpos, dname_len, dname_start, dname_compr_len;
|
||||
d += 4; /* skip TTL */
|
||||
rdatalen = sldns_read_uint16(d); /* read rdata length */
|
||||
d += 2;
|
||||
|
||||
if(rdatalen < 2 /* priority */ + 1 /* 1 length target */)
|
||||
return 0; /* malformed, too short */
|
||||
d += 2; /* skip priority */
|
||||
rdatalen -= 2;
|
||||
oldpos = sldns_buffer_position(pkt);
|
||||
sldns_buffer_set_position(pkt, (size_t)(d - sldns_buffer_begin(pkt)));
|
||||
dname_start = sldns_buffer_position(pkt);
|
||||
dname_len = pkt_dname_len(pkt);
|
||||
dname_compr_len = sldns_buffer_position(pkt) - dname_start;
|
||||
sldns_buffer_set_position(pkt, oldpos);
|
||||
if(dname_len == 0)
|
||||
return 0; /* dname malformed */
|
||||
if(dname_compr_len > rdatalen)
|
||||
return 0; /* malformed */
|
||||
d += dname_compr_len; /* skip target */
|
||||
rdatalen -= dname_compr_len;
|
||||
|
||||
while(rdatalen >= 4) {
|
||||
svcparamkey = sldns_read_uint16(d);
|
||||
data_len = sldns_read_uint16(d+2);
|
||||
d += 4;
|
||||
rdatalen -= 4;
|
||||
|
||||
/* verify that we have data_len data */
|
||||
if(data_len > rdatalen) {
|
||||
/* It is malformed, but if there are addresses
|
||||
* in there it can be rejected. */
|
||||
data_len = rdatalen;
|
||||
}
|
||||
|
||||
if(!data_len)
|
||||
continue; /* no data for the svcparamkey */
|
||||
|
||||
if(svcparamkey == SVCB_KEY_IPV4HINT) {
|
||||
if(svcb_ipv4hint_contains_priv_addr(priv, d, data_len,
|
||||
addr, addrlen))
|
||||
return 1;
|
||||
} else if(svcparamkey == SVCB_KEY_IPV6HINT) {
|
||||
if(svcb_ipv6hint_contains_priv_addr(priv, d, data_len,
|
||||
addr, addrlen))
|
||||
return 1;
|
||||
}
|
||||
d += data_len;
|
||||
rdatalen -= data_len;
|
||||
}
|
||||
/* If rdatalen != 0 here, then the svcb rdata is malformed. */
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if the SVCB and HTTPS rrset is bad.
|
||||
* @param priv: private address lookup struct.
|
||||
* @param pkt: the packet.
|
||||
* @param rrset: the rrset to check.
|
||||
* @return 1 if the entire rrset has to be removed. 0 if not.
|
||||
* It removes RRs if they have private addresses, and log that.
|
||||
*/
|
||||
static int priv_svcb_rrset_bad(struct iter_priv* priv, sldns_buffer* pkt,
|
||||
struct rrset_parse* rrset)
|
||||
{
|
||||
struct rr_parse* rr, *prev = NULL;
|
||||
struct sockaddr_storage addr;
|
||||
socklen_t addrlen = (socklen_t)sizeof(addr);
|
||||
for(rr = rrset->rr_first; rr; rr = rr->next) {
|
||||
if(svcb_rr_contains_priv_addr(priv, pkt, rr, &addr,
|
||||
&addrlen)) {
|
||||
if(msgparse_rrset_remove_rr("sanitize: removing public name with private address", pkt, rrset, prev, rr, &addr, addrlen))
|
||||
return 1;
|
||||
continue;
|
||||
}
|
||||
prev = rr;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
int priv_rrset_bad(struct iter_priv* priv, sldns_buffer* pkt,
|
||||
struct rrset_parse* rrset)
|
||||
{
|
||||
@@ -268,7 +430,11 @@ int priv_rrset_bad(struct iter_priv* priv, sldns_buffer* pkt,
|
||||
}
|
||||
prev = rr;
|
||||
}
|
||||
}
|
||||
} else if(rrset->type == LDNS_RR_TYPE_SVCB ||
|
||||
rrset->type == LDNS_RR_TYPE_HTTPS) {
|
||||
if(priv_svcb_rrset_bad(priv, pkt, rrset))
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -107,7 +107,7 @@ response_type_from_cache(struct dns_msg* msg,
|
||||
enum response_type
|
||||
response_type_from_server(int rdset,
|
||||
struct dns_msg* msg, struct query_info* request, struct delegpt* dp,
|
||||
int* empty_nodata_found)
|
||||
int* empty_nodata_found, int msg_lame_empty, int msg_lame_referral)
|
||||
{
|
||||
uint8_t* origzone = (uint8_t*)"\000"; /* the default */
|
||||
struct ub_packed_rrset_key* s;
|
||||
@@ -122,6 +122,10 @@ response_type_from_server(int rdset,
|
||||
|
||||
/* If the message is NXDOMAIN, then it answers the question. */
|
||||
if(FLAGS_GET_RCODE(msg->rep->flags) == LDNS_RCODE_NXDOMAIN) {
|
||||
if(msg->rep->an_numrrsets == 0 &&
|
||||
msg->rep->ns_numrrsets == 0 &&
|
||||
msg_lame_empty)
|
||||
return RESPONSE_TYPE_LAME;
|
||||
/* make sure its not recursive when we don't want it to */
|
||||
if( (msg->rep->flags&BIT_RA) &&
|
||||
!(msg->rep->flags&BIT_AA) && !rdset)
|
||||
@@ -143,6 +147,10 @@ response_type_from_server(int rdset,
|
||||
if(FLAGS_GET_RCODE(msg->rep->flags) != LDNS_RCODE_NOERROR)
|
||||
return RESPONSE_TYPE_THROWAWAY;
|
||||
|
||||
if(msg->rep->an_numrrsets == 0 && msg->rep->ns_numrrsets == 0 &&
|
||||
msg_lame_empty)
|
||||
return RESPONSE_TYPE_LAME;
|
||||
|
||||
/* Note: TC bit has already been handled */
|
||||
|
||||
if(dp) {
|
||||
@@ -249,13 +257,16 @@ response_type_from_server(int rdset,
|
||||
* which gives ns==zone delegation from cache
|
||||
* without AA bit as well, with nodata nosoa*/
|
||||
/* real answer must be +AA and SOA RFC(2308),
|
||||
* so this is wrong, and we SERVFAIL it if
|
||||
* this is the only possible reply, if it
|
||||
* is misdeployed the THROWAWAY makes us pick
|
||||
* the next server from the selection */
|
||||
if(msg->rep->an_numrrsets==0 &&
|
||||
* this is picked up as lame_referral by the
|
||||
* sanitize step, so it can spot if there
|
||||
* was data in the answer section before
|
||||
* removal. If such data is then removed we
|
||||
* do not want to turn that answer into lame.
|
||||
* But if it was not there, it can be lame. */
|
||||
if(msg_lame_referral &&
|
||||
msg->rep->an_numrrsets==0 &&
|
||||
!(msg->rep->flags&BIT_AA) && !rdset)
|
||||
return RESPONSE_TYPE_THROWAWAY;
|
||||
return RESPONSE_TYPE_LAME;
|
||||
return RESPONSE_TYPE_ANSWER;
|
||||
}
|
||||
/* If we are getting a referral upwards (or to
|
||||
|
||||
@@ -120,10 +120,14 @@ enum response_type response_type_from_cache(struct dns_msg* msg,
|
||||
* @param dp: The delegation point that was being queried
|
||||
* when the response was returned.
|
||||
* @param empty_nodata_found: flag to keep track of empty nodata detection.
|
||||
* @param msg_lame_empty: The scrubber indicates that this empty message
|
||||
* is lame, before it became empty.
|
||||
* @param msg_lame_referral: returned true if the reply has a referral before
|
||||
* scrub.
|
||||
* @return the response type (CNAME or ANSWER).
|
||||
*/
|
||||
enum response_type response_type_from_server(int rdset,
|
||||
struct dns_msg* msg, struct query_info* request, struct delegpt* dp,
|
||||
int* empty_nodata_found);
|
||||
int* empty_nodata_found, int msg_lame_empty, int msg_lame_referral);
|
||||
|
||||
#endif /* ITERATOR_ITER_RESPTYPE_H */
|
||||
|
||||
+194
-15
@@ -285,6 +285,17 @@ synth_cname_rrset(uint8_t** sname, size_t* snamelen, uint8_t* alias,
|
||||
return NULL;
|
||||
memmove(cn->rr_first->ttl_data, rrset->rr_first->ttl_data,
|
||||
sizeof(uint32_t)); /* RFC6672: synth CNAME TTL == DNAME TTL */
|
||||
/* Apply cache TTL policy so DNAME and synthesized CNAME stay equal
|
||||
* and respect cache-min-ttl/cache-max-ttl (same as rdata_copy path). */
|
||||
if(!SERVE_ORIGINAL_TTL) {
|
||||
uint32_t ttl = sldns_read_uint32(cn->rr_first->ttl_data);
|
||||
time_t ttl_t = (time_t)ttl;
|
||||
if(ttl_t < MIN_TTL) ttl_t = MIN_TTL;
|
||||
if(ttl_t > MAX_TTL) ttl_t = MAX_TTL;
|
||||
ttl = (uint32_t)ttl_t;
|
||||
sldns_write_uint32(cn->rr_first->ttl_data, ttl);
|
||||
sldns_write_uint32(rrset->rr_first->ttl_data, ttl);
|
||||
}
|
||||
sldns_write_uint16(cn->rr_first->ttl_data+4, aliaslen);
|
||||
memmove(cn->rr_first->ttl_data+6, alias, aliaslen);
|
||||
cn->rr_first->size = sizeof(uint16_t)+aliaslen;
|
||||
@@ -305,6 +316,20 @@ synth_cname_rrset(uint8_t** sname, size_t* snamelen, uint8_t* alias,
|
||||
return cn;
|
||||
}
|
||||
|
||||
/** Check if the packet has type NS in answer or authority section */
|
||||
static int
|
||||
pkt_contains_ns(struct msg_parse* msg)
|
||||
{
|
||||
struct rrset_parse* rrset;
|
||||
for(rrset = msg->rrset_first; rrset; rrset = rrset->rrset_all_next) {
|
||||
if(rrset->type == LDNS_RR_TYPE_NS &&
|
||||
(rrset->section == LDNS_SECTION_ANSWER ||
|
||||
rrset->section == LDNS_SECTION_AUTHORITY))
|
||||
return 1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
/** check if DNAME applies to a name */
|
||||
static int
|
||||
pkt_strict_sub(sldns_buffer* pkt, uint8_t* sname, uint8_t* dr)
|
||||
@@ -383,6 +408,8 @@ shorten_rrset(sldns_buffer* pkt, struct rrset_parse* rrset, int count)
|
||||
struct rr_parse* rr = rrset->rr_first, *prev = NULL;
|
||||
if(!rr)
|
||||
return;
|
||||
if(count < 1)
|
||||
return; /* cannot leave a still-linked rrset_parse with rr_count == 0 */
|
||||
for(i=0; i<count; i++) {
|
||||
prev = rr;
|
||||
rr = rr->next;
|
||||
@@ -408,6 +435,43 @@ shorten_rrset(sldns_buffer* pkt, struct rrset_parse* rrset, int count)
|
||||
else rrset->rr_first = NULL;
|
||||
}
|
||||
|
||||
/** Shorten RRSIGs list */
|
||||
static void
|
||||
shorten_rrsig(sldns_buffer* pkt, struct rrset_parse* rrset, int count)
|
||||
{
|
||||
/* The too large list of RRSIGs on the RRset is shortened.
|
||||
* This is so that too large content does not overwhelm the cache.
|
||||
* The validator does not validate more than a max number of
|
||||
* RRSIGs as well. */
|
||||
int i;
|
||||
struct rr_parse* rr = rrset->rrsig_first, *prev = NULL;
|
||||
if(!rr)
|
||||
return;
|
||||
for(i=0; i<count; i++) {
|
||||
prev = rr;
|
||||
rr = rr->next;
|
||||
if(!rr)
|
||||
return; /* The RRSIG list is already short. */
|
||||
}
|
||||
if(verbosity >= VERB_QUERY
|
||||
&& rrset->dname_len <= LDNS_MAX_DOMAINLEN) {
|
||||
uint8_t buf[LDNS_MAX_DOMAINLEN+1];
|
||||
dname_pkt_copy(pkt, buf, rrset->dname);
|
||||
log_nametypeclass(VERB_QUERY, "normalize: shorten RRSIGs:",
|
||||
buf, rrset->type, ntohs(rrset->rrset_class));
|
||||
}
|
||||
/* remove further rrsigs */
|
||||
rrset->rrsig_last = prev;
|
||||
rrset->rrsig_count = count;
|
||||
while(rr) {
|
||||
rrset->size -= rr->size;
|
||||
rr = rr->next;
|
||||
}
|
||||
if(rrset->rrsig_last)
|
||||
rrset->rrsig_last->next = NULL;
|
||||
else rrset->rrsig_first = NULL;
|
||||
}
|
||||
|
||||
/**
|
||||
* This routine normalizes a response. This includes removing "irrelevant"
|
||||
* records from the answer and additional sections and (re)synthesizing
|
||||
@@ -418,20 +482,23 @@ shorten_rrset(sldns_buffer* pkt, struct rrset_parse* rrset, int count)
|
||||
* @param qinfo: original query.
|
||||
* @param region: where to allocate synthesized CNAMEs.
|
||||
* @param env: module env with config options.
|
||||
* @param zonename: name of server zone.
|
||||
* @return 0 on error.
|
||||
*/
|
||||
static int
|
||||
scrub_normalize(sldns_buffer* pkt, struct msg_parse* msg,
|
||||
struct query_info* qinfo, struct regional* region,
|
||||
struct module_env* env)
|
||||
struct module_env* env, uint8_t* zonename)
|
||||
{
|
||||
uint8_t* sname = qinfo->qname;
|
||||
size_t snamelen = qinfo->qname_len;
|
||||
struct rrset_parse* rrset, *prev, *nsset=NULL;
|
||||
int cname_length = 0; /* number of CNAMEs, or DNAMEs */
|
||||
int has_answer = 0; /* if answer section contains nonCNAME,nonDNAME */
|
||||
|
||||
if(FLAGS_GET_RCODE(msg->flags) != LDNS_RCODE_NOERROR &&
|
||||
FLAGS_GET_RCODE(msg->flags) != LDNS_RCODE_NXDOMAIN)
|
||||
FLAGS_GET_RCODE(msg->flags) != LDNS_RCODE_NXDOMAIN &&
|
||||
FLAGS_GET_RCODE(msg->flags) != LDNS_RCODE_YXDOMAIN)
|
||||
return 1;
|
||||
|
||||
/* For the ANSWER section, remove all "irrelevant" records and add
|
||||
@@ -443,6 +510,8 @@ scrub_normalize(sldns_buffer* pkt, struct msg_parse* msg,
|
||||
prev = NULL;
|
||||
rrset = msg->rrset_first;
|
||||
while(rrset && rrset->section == LDNS_SECTION_ANSWER) {
|
||||
if((int)rrset->rrsig_count > env->cfg->iter_scrub_rrsig)
|
||||
shorten_rrsig(pkt, rrset, env->cfg->iter_scrub_rrsig);
|
||||
if(cname_length > env->cfg->iter_scrub_cname) {
|
||||
/* Too many CNAMEs, or DNAMEs, from the authority
|
||||
* server, scrub down the length to something
|
||||
@@ -453,8 +522,9 @@ scrub_normalize(sldns_buffer* pkt, struct msg_parse* msg,
|
||||
pkt, msg, prev, &rrset);
|
||||
continue;
|
||||
}
|
||||
if(rrset->type == LDNS_RR_TYPE_DNAME &&
|
||||
pkt_strict_sub(pkt, sname, rrset->dname)) {
|
||||
if(rrset->type == LDNS_RR_TYPE_DNAME &&
|
||||
pkt_strict_sub(pkt, sname, rrset->dname) &&
|
||||
pkt_sub(pkt, rrset->dname, zonename)) {
|
||||
/* check if next rrset is correct CNAME. else,
|
||||
* synthesize a CNAME */
|
||||
struct rrset_parse* nx = rrset->rrset_all_next;
|
||||
@@ -466,10 +536,20 @@ scrub_normalize(sldns_buffer* pkt, struct msg_parse* msg,
|
||||
(unsigned)rrset->rr_count);
|
||||
return 0;
|
||||
}
|
||||
if(has_answer) {
|
||||
remove_rrset("normalize: removing DNAME redirection after answer:",
|
||||
pkt, msg, prev, &rrset);
|
||||
continue;
|
||||
}
|
||||
if(!synth_cname(sname, snamelen, rrset, alias,
|
||||
&aliaslen, pkt)) {
|
||||
verbose(VERB_ALGO, "synthesized CNAME "
|
||||
"too long");
|
||||
if(FLAGS_GET_RCODE(msg->flags) == LDNS_RCODE_YXDOMAIN) {
|
||||
prev = rrset;
|
||||
rrset = rrset->rrset_all_next;
|
||||
continue;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
cname_length++;
|
||||
@@ -495,8 +575,6 @@ scrub_normalize(sldns_buffer* pkt, struct msg_parse* msg,
|
||||
log_err("out of memory synthesizing CNAME");
|
||||
return 0;
|
||||
}
|
||||
/* FIXME: resolve the conflict between synthesized
|
||||
* CNAME ttls and the cache. */
|
||||
rrset = nx;
|
||||
continue;
|
||||
|
||||
@@ -513,12 +591,18 @@ scrub_normalize(sldns_buffer* pkt, struct msg_parse* msg,
|
||||
if(rrset->type == LDNS_RR_TYPE_CNAME) {
|
||||
struct rrset_parse* nx = rrset->rrset_all_next;
|
||||
uint8_t* oldsname = sname;
|
||||
if(has_answer) {
|
||||
remove_rrset("normalize: removing redirection after answer:",
|
||||
pkt, msg, prev, &rrset);
|
||||
continue;
|
||||
}
|
||||
cname_length++;
|
||||
/* see if the next one is a DNAME, if so, swap them */
|
||||
if(nx && nx->section == LDNS_SECTION_ANSWER &&
|
||||
nx->type == LDNS_RR_TYPE_DNAME &&
|
||||
nx->rr_count == 1 &&
|
||||
pkt_strict_sub(pkt, sname, nx->dname)) {
|
||||
pkt_strict_sub(pkt, sname, nx->dname) &&
|
||||
pkt_sub(pkt, nx->dname, zonename)) {
|
||||
/* there is a DNAME after this CNAME, it
|
||||
* is in the ANSWER section, and the DNAME
|
||||
* applies to the name we cover */
|
||||
@@ -590,6 +674,7 @@ scrub_normalize(sldns_buffer* pkt, struct msg_parse* msg,
|
||||
* will be removed by sanitize, so no additional for them */
|
||||
if(dname_pkt_compare(pkt, qinfo->qname, rrset->dname) == 0)
|
||||
mark_additional_rrset(pkt, msg, rrset);
|
||||
has_answer = 1;
|
||||
|
||||
prev = rrset;
|
||||
rrset = rrset->rrset_all_next;
|
||||
@@ -613,6 +698,8 @@ scrub_normalize(sldns_buffer* pkt, struct msg_parse* msg,
|
||||
"RRset:", pkt, msg, prev, &rrset);
|
||||
continue;
|
||||
}
|
||||
if((int)rrset->rrsig_count > env->cfg->iter_scrub_rrsig)
|
||||
shorten_rrsig(pkt, rrset, env->cfg->iter_scrub_rrsig);
|
||||
/* only one NS set allowed in authority section */
|
||||
if(rrset->type==LDNS_RR_TYPE_NS) {
|
||||
/* NS set must be pertinent to the query */
|
||||
@@ -634,6 +721,50 @@ scrub_normalize(sldns_buffer* pkt, struct msg_parse* msg,
|
||||
"RRset:", pkt, msg, prev, &rrset);
|
||||
continue;
|
||||
}
|
||||
/* If the NS set is a promiscuous NS set, scrub that
|
||||
* to remove potential for poisonous contents that
|
||||
* affects other names in the same zone. Remove
|
||||
* promiscuous NS sets in positive answers, that
|
||||
* thus have records in the answer section. Nodata
|
||||
* and nxdomain promiscuous NS sets have been removed
|
||||
* already. Since the NS rrset is scrubbed, its
|
||||
* address records are also not marked to be allowed
|
||||
* and are removed later. */
|
||||
if(FLAGS_GET_RCODE(msg->flags) == LDNS_RCODE_NOERROR &&
|
||||
msg->an_rrsets != 0 &&
|
||||
env->cfg->iter_scrub_promiscuous) {
|
||||
remove_rrset("normalize: removing promiscuous "
|
||||
"RRset:", pkt, msg, prev, &rrset);
|
||||
continue;
|
||||
}
|
||||
/* Also delete promiscuous NS for other RCODEs */
|
||||
if(FLAGS_GET_RCODE(msg->flags) != LDNS_RCODE_NOERROR
|
||||
&& env->cfg->iter_scrub_promiscuous) {
|
||||
remove_rrset("normalize: removing promiscuous "
|
||||
"RRset:", pkt, msg, prev, &rrset);
|
||||
continue;
|
||||
}
|
||||
/* Also delete promiscuous NS for NOERROR with nodata
|
||||
* for authoritative answers, not for delegations.
|
||||
* NOERROR with an_rrsets!=0 already handled.
|
||||
* Also NOERROR and soa_in_auth already handled.
|
||||
* NOERROR with an_rrsets==0, and not a referral.
|
||||
* referral is (NS not the zonename, noSOA).
|
||||
*/
|
||||
if(FLAGS_GET_RCODE(msg->flags) == LDNS_RCODE_NOERROR
|
||||
&& msg->an_rrsets == 0
|
||||
&& !(dname_pkt_compare(pkt, rrset->dname,
|
||||
zonename) != 0 && !soa_in_auth(msg))
|
||||
&& env->cfg->iter_scrub_promiscuous) {
|
||||
remove_rrset("normalize: removing promiscuous "
|
||||
"RRset:", pkt, msg, prev, &rrset);
|
||||
continue;
|
||||
}
|
||||
if(ntohs(rrset->rrset_class) != qinfo->qclass) {
|
||||
remove_rrset("normalize: removing other class "
|
||||
"RRset:", pkt, msg, prev, &rrset);
|
||||
continue;
|
||||
}
|
||||
if(nsset == NULL) {
|
||||
nsset = rrset;
|
||||
} else {
|
||||
@@ -679,7 +810,13 @@ scrub_normalize(sldns_buffer* pkt, struct msg_parse* msg,
|
||||
rrset->rrset_all_next = NULL;
|
||||
return 1;
|
||||
}
|
||||
mark_additional_rrset(pkt, msg, rrset);
|
||||
/* Only mark glue as allowed for type NS in the authority
|
||||
* section. Other RR types do not get glue for them, it
|
||||
* is allowed from the answer section, but not authority
|
||||
* so that a message can not have address records cached
|
||||
* as a side effect to the query. */
|
||||
if(rrset->type==LDNS_RR_TYPE_NS)
|
||||
mark_additional_rrset(pkt, msg, rrset);
|
||||
prev = rrset;
|
||||
rrset = rrset->rrset_all_next;
|
||||
}
|
||||
@@ -716,6 +853,8 @@ scrub_normalize(sldns_buffer* pkt, struct msg_parse* msg,
|
||||
"RRset:", pkt, msg, prev, &rrset);
|
||||
continue;
|
||||
}
|
||||
if((int)rrset->rrsig_count > env->cfg->iter_scrub_rrsig)
|
||||
shorten_rrsig(pkt, rrset, env->cfg->iter_scrub_rrsig);
|
||||
prev = rrset;
|
||||
rrset = rrset->rrset_all_next;
|
||||
}
|
||||
@@ -862,12 +1001,20 @@ scrub_sanitize_rr_length(sldns_buffer* pkt, struct msg_parse* msg,
|
||||
* @param env: module environment with config and cache.
|
||||
* @param ie: iterator environment with private address data.
|
||||
* @param qstate: for setting errinf for EDE error messages.
|
||||
* @param pkt_before_NS: if the packet had type NS before scrub. If that
|
||||
* is removed now, that indicates this may have been lame.
|
||||
* @param msg_lame_empty: returned true if the empty packet is lame.
|
||||
* @param msg_lame_referral: returned true if the reply has a referral before
|
||||
* scrub.
|
||||
* @param rdset: if RD bit was sent in query sent by unbound.
|
||||
* @return 0 on error.
|
||||
*/
|
||||
static int
|
||||
scrub_sanitize(sldns_buffer* pkt, struct msg_parse* msg,
|
||||
struct query_info* qinfo, uint8_t* zonename, struct module_env* env,
|
||||
struct iter_env* ie, struct module_qstate* qstate)
|
||||
struct iter_env* ie, struct module_qstate* qstate,
|
||||
int pkt_before_NS, int* msg_lame_empty, int* msg_lame_referral,
|
||||
int rdset)
|
||||
{
|
||||
int del_addi = 0; /* if additional-holding rrsets are deleted, we
|
||||
do not trust the normalized additional-A-AAAA any more */
|
||||
@@ -926,8 +1073,10 @@ scrub_sanitize(sldns_buffer* pkt, struct msg_parse* msg,
|
||||
}
|
||||
|
||||
/* remove private addresses */
|
||||
if( (rrset->type == LDNS_RR_TYPE_A ||
|
||||
rrset->type == LDNS_RR_TYPE_AAAA)) {
|
||||
if(rrset->type == LDNS_RR_TYPE_A ||
|
||||
rrset->type == LDNS_RR_TYPE_AAAA ||
|
||||
rrset->type == LDNS_RR_TYPE_SVCB ||
|
||||
rrset->type == LDNS_RR_TYPE_HTTPS) {
|
||||
|
||||
/* do not set servfail since this leads to too
|
||||
* many drops of other people using rfc1918 space */
|
||||
@@ -1022,6 +1171,21 @@ scrub_sanitize(sldns_buffer* pkt, struct msg_parse* msg,
|
||||
prev = rrset;
|
||||
rrset = rrset->rrset_all_next;
|
||||
}
|
||||
|
||||
/* If the packet is empty now, but it was not before. And there
|
||||
* was type NS in authority, then that indicates the answer is lame. */
|
||||
if(msg->rrset_first == NULL && pkt_before_NS) {
|
||||
*msg_lame_empty = 1;
|
||||
verbose(VERB_ALGO, "sanitize: empty message had referral to NS before, marked as lame");
|
||||
} else if(pkt_before_NS && msg->an_rrsets==0 &&
|
||||
!(msg->flags&BIT_AA) && !rdset) {
|
||||
/* If the packet is now a referral, not really a nodata,
|
||||
* then if it was also with an empty answer section before,
|
||||
* it is also lame. */
|
||||
*msg_lame_referral = 1;
|
||||
verbose(VERB_ALGO, "sanitize: message has referral not answer, marked as lame");
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
@@ -1029,11 +1193,15 @@ int
|
||||
scrub_message(sldns_buffer* pkt, struct msg_parse* msg,
|
||||
struct query_info* qinfo, uint8_t* zonename, struct regional* region,
|
||||
struct module_env* env, struct module_qstate* qstate,
|
||||
struct iter_env* ie)
|
||||
struct iter_env* ie, int* msg_lame_empty, int* msg_lame_referral,
|
||||
int rdset)
|
||||
{
|
||||
int pkt_before_NS;
|
||||
/* basic sanity checks */
|
||||
log_nametypeclass(VERB_ALGO, "scrub for", zonename, LDNS_RR_TYPE_NS,
|
||||
qinfo->qclass);
|
||||
*msg_lame_empty = 0;
|
||||
*msg_lame_referral = 0;
|
||||
if(msg->qdcount > 1)
|
||||
return 0;
|
||||
if( !(msg->flags&BIT_QR) )
|
||||
@@ -1044,7 +1212,8 @@ scrub_message(sldns_buffer* pkt, struct msg_parse* msg,
|
||||
/* this is not required for basic operation but is a forgery
|
||||
* resistance (security) feature */
|
||||
if((FLAGS_GET_RCODE(msg->flags) == LDNS_RCODE_NOERROR ||
|
||||
FLAGS_GET_RCODE(msg->flags) == LDNS_RCODE_NXDOMAIN) &&
|
||||
FLAGS_GET_RCODE(msg->flags) == LDNS_RCODE_NXDOMAIN ||
|
||||
FLAGS_GET_RCODE(msg->flags) == LDNS_RCODE_YXDOMAIN) &&
|
||||
msg->qdcount == 0)
|
||||
return 0;
|
||||
|
||||
@@ -1057,11 +1226,21 @@ scrub_message(sldns_buffer* pkt, struct msg_parse* msg,
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* If the packet contains type NS in authority before scrub,
|
||||
* like a self referral. With the answer section empty, it
|
||||
* was not AA, the query was not sent with RD, with NS in auth,
|
||||
* and no SOA in auth. For a negative answer, type SOA is present.
|
||||
* This detects certain lameness if after has removed that. */
|
||||
pkt_before_NS = msg->an_rrsets == 0 &&
|
||||
!(msg->flags&BIT_AA) && !rdset &&
|
||||
pkt_contains_ns(msg) && !soa_in_auth(msg);
|
||||
|
||||
/* normalize the response, this cleans up the additional. */
|
||||
if(!scrub_normalize(pkt, msg, qinfo, region, env))
|
||||
if(!scrub_normalize(pkt, msg, qinfo, region, env, zonename))
|
||||
return 0;
|
||||
/* delete all out-of-zone information */
|
||||
if(!scrub_sanitize(pkt, msg, qinfo, zonename, env, ie, qstate))
|
||||
if(!scrub_sanitize(pkt, msg, qinfo, zonename, env, ie, qstate,
|
||||
pkt_before_NS, msg_lame_empty, msg_lame_referral, rdset))
|
||||
return 0;
|
||||
return 1;
|
||||
}
|
||||
|
||||
@@ -62,11 +62,16 @@ struct module_qstate;
|
||||
* @param env: module environment with config settings and cache.
|
||||
* @param qstate: for setting errinf for EDE error messages.
|
||||
* @param ie: iterator module environment data.
|
||||
* @param msg_lame_empty: returned true if the empty packet is lame.
|
||||
* @param msg_lame_referral: returned true if the reply has a referral before
|
||||
* scrub.
|
||||
* @param rdset: if RD bit was sent in query sent by unbound.
|
||||
* @return: false if the message is total waste. true if scrubbed with success.
|
||||
*/
|
||||
int scrub_message(struct sldns_buffer* pkt, struct msg_parse* msg,
|
||||
struct query_info* qinfo, uint8_t* zonename, struct regional* regional,
|
||||
struct module_env* env, struct module_qstate* qstate,
|
||||
struct iter_env* ie);
|
||||
struct iter_env* ie, int* msg_lame_empty, int* msg_lame_referral,
|
||||
int rdset);
|
||||
|
||||
#endif /* ITERATOR_ITER_SCRUB_H */
|
||||
|
||||
+56
-5
@@ -253,7 +253,9 @@ iter_apply_cfg(struct iter_env* iter_env, struct config_file* cfg)
|
||||
return 1;
|
||||
}
|
||||
|
||||
/** filter out unsuitable targets
|
||||
/** filter out unsuitable targets.
|
||||
* Applies NAT64 if needed as well by replacing the IPv4 with the synthesized
|
||||
* IPv6 address.
|
||||
* @param iter_env: iterator environment with ipv6-support flag.
|
||||
* @param env: module environment with infra cache.
|
||||
* @param name: zone name
|
||||
@@ -306,9 +308,30 @@ iter_filter_unsuitable(struct iter_env* iter_env, struct module_env* env,
|
||||
if(a->bogus)
|
||||
return -1; /* address of server is bogus */
|
||||
if(donotq_lookup(iter_env->donotq, &a->addr, a->addrlen)) {
|
||||
log_addr(VERB_ALGO, "skip addr on the donotquery list",
|
||||
&a->addr, a->addrlen);
|
||||
return -1; /* server is on the donotquery list */
|
||||
if(iter_env->nat64.use_nat64 &&
|
||||
addr_is_ip6(&a->addr, a->addrlen) &&
|
||||
a->addrlen == iter_env->nat64.nat64_prefix_addrlen &&
|
||||
addr_in_common(&a->addr, 128,
|
||||
&iter_env->nat64.nat64_prefix_addr,
|
||||
iter_env->nat64.nat64_prefix_net,
|
||||
iter_env->nat64.nat64_prefix_addrlen) ==
|
||||
iter_env->nat64.nat64_prefix_net) {
|
||||
/* The NAT64 is enabled, and address is IPv6, it is
|
||||
* in the NAT64 prefix. It is allowed.
|
||||
* So that in an IPv6-only cluster without internet
|
||||
* access, that makes the NAT64 translation continue
|
||||
* to work. The NAT64 prefix is allowed. */
|
||||
/* Otherwise, after a timeout, the already NAT64
|
||||
* translated address would be treated differently,
|
||||
* and that causes confusion. */
|
||||
log_addr(VERB_ALGO, "the addr is on the donotquery "
|
||||
"list, but allowed because it is NAT64",
|
||||
&a->addr, a->addrlen);
|
||||
} else {
|
||||
log_addr(VERB_ALGO, "skip addr on the donotquery list",
|
||||
&a->addr, a->addrlen);
|
||||
return -1; /* server is on the donotquery list */
|
||||
}
|
||||
}
|
||||
if(!iter_env->supports_ipv6 && addr_is_ip6(&a->addr, a->addrlen)) {
|
||||
return -1; /* there is no ip6 available */
|
||||
@@ -317,6 +340,20 @@ iter_filter_unsuitable(struct iter_env* iter_env, struct module_env* env,
|
||||
!addr_is_ip6(&a->addr, a->addrlen)) {
|
||||
return -1; /* there is no ip4 available */
|
||||
}
|
||||
if(iter_env->nat64.use_nat64 && !addr_is_ip6(&a->addr, a->addrlen)) {
|
||||
struct sockaddr_storage real_addr;
|
||||
socklen_t real_addrlen;
|
||||
addr_to_nat64(&a->addr, &iter_env->nat64.nat64_prefix_addr,
|
||||
iter_env->nat64.nat64_prefix_addrlen,
|
||||
iter_env->nat64.nat64_prefix_net,
|
||||
&real_addr, &real_addrlen);
|
||||
log_name_addr(VERB_QUERY, "NAT64 apply: from: ",
|
||||
name, &a->addr, a->addrlen);
|
||||
log_name_addr(VERB_QUERY, "NAT64 apply: to: ",
|
||||
name, &real_addr, real_addrlen);
|
||||
a->addr = real_addr;
|
||||
a->addrlen = real_addrlen;
|
||||
}
|
||||
/* check lameness - need zone , class info */
|
||||
if(infra_get_lame_rtt(env->infra_cache, &a->addr, a->addrlen,
|
||||
name, namelen, qtype, &lame, &dnsseclame, &reclame,
|
||||
@@ -1276,7 +1313,8 @@ iter_lookup_parent_NS_from_cache(struct module_env* env, struct delegpt* dp,
|
||||
log_rrset_key(VERB_ALGO, "found parent-side NS in cache", akey);
|
||||
dp->has_parent_side_NS = 1;
|
||||
/* and mark the new names as lame */
|
||||
if(!delegpt_rrset_add_ns(dp, region, akey, 1)) {
|
||||
if(!delegpt_rrset_add_ns(dp, region, akey, 1,
|
||||
deleg_port_number(env))) {
|
||||
lock_rw_unlock(&akey->entry.lock);
|
||||
return 0;
|
||||
}
|
||||
@@ -1511,6 +1549,11 @@ iter_stub_fwd_no_cache(struct module_qstate *qstate, struct query_info *qinf,
|
||||
struct delegpt *dp;
|
||||
int nolock = 1;
|
||||
|
||||
log_assert((retdpname && retdpnamelen
|
||||
&& dpname_storage && dpname_storage_len > 0) ||
|
||||
(retdpname == NULL && retdpnamelen == NULL
|
||||
&& dpname_storage == NULL && dpname_storage_len == 0));
|
||||
|
||||
/* Check for stub. */
|
||||
/* Lock both forwards and hints for atomic read. */
|
||||
lock_rw_rdlock(&qstate->env->fwds->lock);
|
||||
@@ -1661,3 +1704,11 @@ iter_make_minimal(struct reply_info* rep)
|
||||
rep->ar_numrrsets = 0;
|
||||
rep->rrset_count -= rem;
|
||||
}
|
||||
|
||||
int
|
||||
deleg_port_number(struct module_env* env)
|
||||
{
|
||||
if(env->cfg->ssl_upstream)
|
||||
return env->cfg->ssl_port;
|
||||
return -1;
|
||||
}
|
||||
|
||||
@@ -84,6 +84,7 @@ int iter_apply_cfg(struct iter_env* iter_env, struct config_file* cfg);
|
||||
/**
|
||||
* Select a valid, nice target to send query to.
|
||||
* Sorting and removing unsuitable targets is combined.
|
||||
* Adds records to the infra cache if not already there.
|
||||
*
|
||||
* @param iter_env: iterator module global state, with ip6 enabled and
|
||||
* do-not-query-addresses.
|
||||
@@ -482,4 +483,7 @@ void limit_nsec_ttl(struct dns_msg* msg);
|
||||
*/
|
||||
void iter_make_minimal(struct reply_info* rep);
|
||||
|
||||
/** See if we need a different port number */
|
||||
int deleg_port_number(struct module_env* env);
|
||||
|
||||
#endif /* ITERATOR_ITER_UTILS_H */
|
||||
|
||||
+159
-67
@@ -81,7 +81,8 @@ int BLACKLIST_PENALTY = (120000*4);
|
||||
/** Timeout when only a single probe query per IP is allowed. */
|
||||
int PROBE_MAXRTO = PROBE_MAXRTO_DEFAULT; /* in msec */
|
||||
|
||||
static void target_count_increase_nx(struct iter_qstate* iq, int num);
|
||||
static void target_count_increase_nx(struct module_qstate* qstate,
|
||||
struct iter_qstate* iq, int num);
|
||||
|
||||
int
|
||||
iter_init(struct module_env* env, int id)
|
||||
@@ -250,7 +251,7 @@ error_supers(struct module_qstate* qstate, int id, struct module_qstate* super)
|
||||
if((dpns->got4 == 2 || (!ie->supports_ipv4 && !ie->nat64.use_nat64)) &&
|
||||
(dpns->got6 == 2 || !ie->supports_ipv6)) {
|
||||
dpns->resolved = 1; /* mark as failed */
|
||||
target_count_increase_nx(super_iq, 1);
|
||||
target_count_increase_nx(super, super_iq, 1);
|
||||
}
|
||||
}
|
||||
if(qstate->qinfo.qtype == LDNS_RR_TYPE_NS) {
|
||||
@@ -297,6 +298,7 @@ error_response_cache(struct module_qstate* qstate, int id, int rcode)
|
||||
struct reply_info err;
|
||||
struct msgreply_entry* msg;
|
||||
if(qstate->no_cache_store) {
|
||||
qstate->error_response_cache = 1;
|
||||
return error_response(qstate, id, rcode);
|
||||
}
|
||||
if(qstate->prefetch_leeway > NORR_TTL) {
|
||||
@@ -733,7 +735,7 @@ is_caps_whitelisted(struct iter_env* ie, struct iter_qstate* iq)
|
||||
* created for the parent query.
|
||||
*/
|
||||
static void
|
||||
target_count_create(struct iter_qstate* iq)
|
||||
target_count_create(struct module_qstate* qstate, struct iter_qstate* iq)
|
||||
{
|
||||
if(!iq->target_count) {
|
||||
iq->target_count = (int*)calloc(TARGET_COUNT_MAX, sizeof(int));
|
||||
@@ -741,33 +743,57 @@ target_count_create(struct iter_qstate* iq)
|
||||
if(iq->target_count) {
|
||||
iq->target_count[TARGET_COUNT_REF] = 1;
|
||||
iq->nxns_dp = (uint8_t**)calloc(1, sizeof(uint8_t*));
|
||||
/* continue global quota from where it was. */
|
||||
if(qstate->global_quota_reached >
|
||||
iq->target_count[TARGET_COUNT_GLOBAL_QUOTA])
|
||||
iq->target_count[TARGET_COUNT_GLOBAL_QUOTA] =
|
||||
qstate->global_quota_reached;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
target_count_increase(struct iter_qstate* iq, int num)
|
||||
target_count_store(struct module_qstate* qstate, struct iter_qstate* iq)
|
||||
{
|
||||
target_count_create(iq);
|
||||
if(iq->target_count) {
|
||||
/* By storing the global quota counter, it stays
|
||||
* there to be picked up if the module is restarted,
|
||||
* eg. due to a validator retry, and then the
|
||||
* target_count_create routine picks it up. */
|
||||
if(iq->target_count[TARGET_COUNT_GLOBAL_QUOTA] >
|
||||
qstate->global_quota_reached)
|
||||
qstate->global_quota_reached =
|
||||
iq->target_count[TARGET_COUNT_GLOBAL_QUOTA];
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
target_count_increase(struct module_qstate* qstate,
|
||||
struct iter_qstate* iq, int num)
|
||||
{
|
||||
target_count_create(qstate, iq);
|
||||
if(iq->target_count)
|
||||
iq->target_count[TARGET_COUNT_QUERIES] += num;
|
||||
iq->dp_target_count++;
|
||||
}
|
||||
|
||||
static void
|
||||
target_count_increase_nx(struct iter_qstate* iq, int num)
|
||||
target_count_increase_nx(struct module_qstate* qstate,
|
||||
struct iter_qstate* iq, int num)
|
||||
{
|
||||
target_count_create(iq);
|
||||
target_count_create(qstate, iq);
|
||||
if(iq->target_count)
|
||||
iq->target_count[TARGET_COUNT_NX] += num;
|
||||
}
|
||||
|
||||
static void
|
||||
target_count_increase_global_quota(struct iter_qstate* iq, int num)
|
||||
target_count_increase_global_quota(struct module_qstate* qstate,
|
||||
struct iter_qstate* iq, int num)
|
||||
{
|
||||
target_count_create(iq);
|
||||
target_count_create(qstate, iq);
|
||||
if(iq->target_count)
|
||||
iq->target_count[TARGET_COUNT_GLOBAL_QUOTA] += num;
|
||||
target_count_store(qstate, iq);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -829,7 +855,7 @@ generate_sub_request(uint8_t* qname, size_t qnamelen, uint16_t qtype,
|
||||
struct mesh_state* sub = NULL;
|
||||
fptr_ok(fptr_whitelist_modenv_add_sub(
|
||||
qstate->env->add_sub));
|
||||
if(!(*qstate->env->add_sub)(qstate, &qinf,
|
||||
if(!(*qstate->env->add_sub)(qstate, &qinf, NULL,
|
||||
qflags, prime, valrec, &subq, &sub)){
|
||||
return 0;
|
||||
}
|
||||
@@ -838,8 +864,8 @@ generate_sub_request(uint8_t* qname, size_t qnamelen, uint16_t qtype,
|
||||
/* attach subquery, lookup existing or make a new one */
|
||||
fptr_ok(fptr_whitelist_modenv_attach_sub(
|
||||
qstate->env->attach_sub));
|
||||
if(!(*qstate->env->attach_sub)(qstate, &qinf, qflags, prime,
|
||||
valrec, &subq)) {
|
||||
if(!(*qstate->env->attach_sub)(qstate, &qinf, NULL, qflags,
|
||||
prime, valrec, &subq)) {
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
@@ -860,7 +886,7 @@ generate_sub_request(uint8_t* qname, size_t qnamelen, uint16_t qtype,
|
||||
subiq = (struct iter_qstate*)subq->minfo[id];
|
||||
memset(subiq, 0, sizeof(*subiq));
|
||||
subiq->num_target_queries = 0;
|
||||
target_count_create(iq);
|
||||
target_count_create(qstate, iq);
|
||||
subiq->target_count = iq->target_count;
|
||||
if(iq->target_count) {
|
||||
iq->target_count[TARGET_COUNT_REF] ++; /* extra reference */
|
||||
@@ -1485,6 +1511,7 @@ processInitRequest(struct module_qstate* qstate, struct iter_qstate* iq,
|
||||
verbose(VERB_ALGO, "no-cache set, going to the network");
|
||||
qstate->no_cache_lookup = 1;
|
||||
qstate->no_cache_store = 1;
|
||||
qstate->fwd_stub_no_cache = 1;
|
||||
msg = NULL;
|
||||
} else if(qstate->blacklist) {
|
||||
/* if cache, or anything else, was blacklisted then
|
||||
@@ -1504,7 +1531,7 @@ processInitRequest(struct module_qstate* qstate, struct iter_qstate* iq,
|
||||
msg = val_neg_getmsg(qstate->env->neg_cache, &iq->qchase,
|
||||
qstate->region, qstate->env->rrset_cache,
|
||||
qstate->env->scratch_buffer,
|
||||
*qstate->env->now, 1/*add SOA*/, NULL,
|
||||
*qstate->env->now, 1/*add SOA*/, dpname,
|
||||
qstate->env->cfg);
|
||||
}
|
||||
/* item taken from cache does not match our query name, thus
|
||||
@@ -2152,6 +2179,7 @@ processLastResort(struct module_qstate* qstate, struct iter_qstate* iq,
|
||||
verbose(VERB_QUERY, "configured stub or forward servers failed -- returning SERVFAIL");
|
||||
return error_response_cache(qstate, id, LDNS_RCODE_SERVFAIL);
|
||||
}
|
||||
iq->dp->fallback_to_parent_side_NS = 1;
|
||||
if(qstate->env->cfg->harden_unverified_glue) {
|
||||
if(!cache_fill_missing(qstate->env, iq->qchase.qclass,
|
||||
qstate->region, iq->dp, PACKED_RRSET_UNVERIFIED_GLUE))
|
||||
@@ -2180,6 +2208,10 @@ processLastResort(struct module_qstate* qstate, struct iter_qstate* iq,
|
||||
a->lame, a->tls_auth_name, -1, NULL);
|
||||
}
|
||||
lock_rw_unlock(&qstate->env->hints->lock);
|
||||
/* copy over some configuration since we update the
|
||||
* delegation point in place */
|
||||
iq->dp->tcp_upstream = dp->tcp_upstream;
|
||||
iq->dp->ssl_upstream = dp->ssl_upstream;
|
||||
}
|
||||
iq->dp->has_parent_side_NS = 1;
|
||||
} else if(!iq->dp->has_parent_side_NS) {
|
||||
@@ -2228,7 +2260,7 @@ processLastResort(struct module_qstate* qstate, struct iter_qstate* iq,
|
||||
return error_response_cache(qstate, id, LDNS_RCODE_SERVFAIL);
|
||||
}
|
||||
iq->num_target_queries += qs;
|
||||
target_count_increase(iq, qs);
|
||||
target_count_increase(qstate, iq, qs);
|
||||
if(qs != 0) {
|
||||
qstate->ext_state[id] = module_wait_subquery;
|
||||
return 0; /* and wait for them */
|
||||
@@ -2284,7 +2316,7 @@ processLastResort(struct module_qstate* qstate, struct iter_qstate* iq,
|
||||
* lookups at a time. */
|
||||
verbose(VERB_ALGO, "try parent-side glue lookup");
|
||||
iq->num_target_queries += query_count;
|
||||
target_count_increase(iq, query_count);
|
||||
target_count_increase(qstate, iq, query_count);
|
||||
qstate->ext_state[id] = module_wait_subquery;
|
||||
return 0;
|
||||
}
|
||||
@@ -2304,7 +2336,7 @@ processLastResort(struct module_qstate* qstate, struct iter_qstate* iq,
|
||||
if(query_count != 0) { /* suspend to await results */
|
||||
verbose(VERB_ALGO, "try parent-side glue lookup");
|
||||
iq->num_target_queries += query_count;
|
||||
target_count_increase(iq, query_count);
|
||||
target_count_increase(qstate, iq, query_count);
|
||||
qstate->ext_state[id] = module_wait_subquery;
|
||||
return 0;
|
||||
}
|
||||
@@ -2360,6 +2392,12 @@ processDSNSFind(struct module_qstate* qstate, struct iter_qstate* iq, int id)
|
||||
|
||||
/* go up one (more) step, until we hit the dp, if so, end */
|
||||
dname_remove_label(&iq->dsns_point, &iq->dsns_point_len);
|
||||
if(++iq->dsns_count > MAX_DSNS_FIND_COUNT) {
|
||||
verbose(VERB_QUERY, "DS NS search exceeded %d labels",
|
||||
MAX_DSNS_FIND_COUNT);
|
||||
errinf(qstate, "DS NS search exceeded label limit");
|
||||
return error_response_cache(qstate, id, LDNS_RCODE_SERVFAIL);
|
||||
}
|
||||
if(query_dname_compare(iq->dsns_point, iq->dp->name) == 0) {
|
||||
/* there was no inbetween nameserver, use the old delegation
|
||||
* point again. And this time, because dsns_point is nonNULL
|
||||
@@ -2431,8 +2469,6 @@ processQueryTargets(struct module_qstate* qstate, struct iter_qstate* iq,
|
||||
int tf_policy;
|
||||
struct delegpt_addr* target;
|
||||
struct outbound_entry* outq;
|
||||
struct sockaddr_storage real_addr;
|
||||
socklen_t real_addrlen;
|
||||
int auth_fallback = 0;
|
||||
uint8_t* qout_orig = NULL;
|
||||
size_t qout_orig_len = 0;
|
||||
@@ -2768,7 +2804,8 @@ processQueryTargets(struct module_qstate* qstate, struct iter_qstate* iq,
|
||||
}
|
||||
/* if the mesh query list is full, then do not waste cpu and sockets to
|
||||
* fetch promiscuous targets. They can be looked up when needed. */
|
||||
if(can_do_promisc && !mesh_jostle_exceeded(qstate->env->mesh)) {
|
||||
if(!iq->dp->fallback_to_parent_side_NS && can_do_promisc
|
||||
&& !mesh_jostle_exceeded(qstate->env->mesh)) {
|
||||
tf_policy = ie->target_fetch_policy[iq->depth];
|
||||
}
|
||||
|
||||
@@ -2783,7 +2820,7 @@ processQueryTargets(struct module_qstate* qstate, struct iter_qstate* iq,
|
||||
return error_response_cache(qstate, id, LDNS_RCODE_SERVFAIL);
|
||||
}
|
||||
iq->num_target_queries += extra;
|
||||
target_count_increase(iq, extra);
|
||||
target_count_increase(qstate, iq, extra);
|
||||
if(iq->num_target_queries > 0) {
|
||||
/* wait to get all targets, we want to try em */
|
||||
verbose(VERB_ALGO, "wait for all targets for fallback");
|
||||
@@ -2834,7 +2871,7 @@ processQueryTargets(struct module_qstate* qstate, struct iter_qstate* iq,
|
||||
/* errors ignored, these targets are not strictly necessary for
|
||||
* this result, we do not have to reply with SERVFAIL */
|
||||
iq->num_target_queries += extra;
|
||||
target_count_increase(iq, extra);
|
||||
target_count_increase(qstate, iq, extra);
|
||||
}
|
||||
|
||||
/* Add the current set of unused targets to our queue. */
|
||||
@@ -2957,7 +2994,7 @@ processQueryTargets(struct module_qstate* qstate, struct iter_qstate* iq,
|
||||
LDNS_RCODE_SERVFAIL);
|
||||
}
|
||||
iq->num_target_queries += qs;
|
||||
target_count_increase(iq, qs);
|
||||
target_count_increase(qstate, iq, qs);
|
||||
}
|
||||
/* Since a target query might have been made, we
|
||||
* need to check again. */
|
||||
@@ -3017,7 +3054,7 @@ processQueryTargets(struct module_qstate* qstate, struct iter_qstate* iq,
|
||||
* this result, we do not have to reply with SERVFAIL */
|
||||
if(extra > 0) {
|
||||
iq->num_target_queries += extra;
|
||||
target_count_increase(iq, extra);
|
||||
target_count_increase(qstate, iq, extra);
|
||||
check_waiting_queries(iq, qstate, id);
|
||||
/* undo qname minimise step because we'll get back here
|
||||
* to do it again */
|
||||
@@ -3030,7 +3067,7 @@ processQueryTargets(struct module_qstate* qstate, struct iter_qstate* iq,
|
||||
}
|
||||
}
|
||||
|
||||
target_count_increase_global_quota(iq, 1);
|
||||
target_count_increase_global_quota(qstate, iq, 1);
|
||||
if(iq->target_count && iq->target_count[TARGET_COUNT_GLOBAL_QUOTA]
|
||||
> MAX_GLOBAL_QUOTA) {
|
||||
char s[LDNS_MAX_DOMAINLEN];
|
||||
@@ -3043,7 +3080,9 @@ processQueryTargets(struct module_qstate* qstate, struct iter_qstate* iq,
|
||||
|
||||
/* Do not check ratelimit for forwarding queries or if we already got a
|
||||
* pass. */
|
||||
sq_check_ratelimit = (!(iq->chase_flags & BIT_RD) && !iq->ratelimit_ok);
|
||||
sq_check_ratelimit = ((!(iq->chase_flags & BIT_RD) &&
|
||||
!iq->ratelimit_ok));
|
||||
iq->ratelimit_incremented = 0;
|
||||
/* We have a valid target. */
|
||||
if(verbosity >= VERB_QUERY) {
|
||||
log_query_info(VERB_QUERY, "sending query:", &iq->qinfo_out);
|
||||
@@ -3054,17 +3093,6 @@ processQueryTargets(struct module_qstate* qstate, struct iter_qstate* iq,
|
||||
iq->dnssec_lame_query?" but lame_query anyway": "");
|
||||
}
|
||||
|
||||
real_addr = target->addr;
|
||||
real_addrlen = target->addrlen;
|
||||
|
||||
if(ie->nat64.use_nat64 && target->addr.ss_family == AF_INET) {
|
||||
addr_to_nat64(&target->addr, &ie->nat64.nat64_prefix_addr,
|
||||
ie->nat64.nat64_prefix_addrlen, ie->nat64.nat64_prefix_net,
|
||||
&real_addr, &real_addrlen);
|
||||
log_name_addr(VERB_QUERY, "applied NAT64:",
|
||||
iq->dp->name, &real_addr, real_addrlen);
|
||||
}
|
||||
|
||||
fptr_ok(fptr_whitelist_modenv_send_query(qstate->env->send_query));
|
||||
outq = (*qstate->env->send_query)(&iq->qinfo_out,
|
||||
iq->chase_flags | (iq->chase_to_rd?BIT_RD:0),
|
||||
@@ -3076,11 +3104,12 @@ processQueryTargets(struct module_qstate* qstate, struct iter_qstate* iq,
|
||||
!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(
|
||||
ie, iq), sq_check_ratelimit, &real_addr, real_addrlen,
|
||||
ie, iq), sq_check_ratelimit, &target->addr, target->addrlen,
|
||||
iq->dp->name, iq->dp->namelen,
|
||||
(iq->dp->tcp_upstream || qstate->env->cfg->tcp_upstream),
|
||||
(iq->dp->ssl_upstream || qstate->env->cfg->ssl_upstream),
|
||||
target->tls_auth_name, qstate, &sq_was_ratelimited);
|
||||
target->tls_auth_name, qstate, &sq_was_ratelimited,
|
||||
&iq->ratelimit_incremented);
|
||||
if(!outq) {
|
||||
if(sq_was_ratelimited) {
|
||||
lock_basic_lock(&ie->queries_ratelimit_lock);
|
||||
@@ -3093,7 +3122,7 @@ processQueryTargets(struct module_qstate* qstate, struct iter_qstate* iq,
|
||||
return error_response_cache(qstate, id, LDNS_RCODE_SERVFAIL);
|
||||
}
|
||||
log_addr(VERB_QUERY, "error sending query to auth server",
|
||||
&real_addr, real_addrlen);
|
||||
&target->addr, target->addrlen);
|
||||
if(qstate->env->cfg->qname_minimisation)
|
||||
iq->minimisation_state = SKIP_MINIMISE_STATE;
|
||||
return next_state(iq, QUERYTARGETS_STATE);
|
||||
@@ -3118,7 +3147,6 @@ find_NS(struct reply_info* rep, size_t from, size_t to)
|
||||
return NULL;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Process the query response. All queries end up at this state first. This
|
||||
* process generally consists of analyzing the response and routing the
|
||||
@@ -3160,7 +3188,8 @@ processQueryResponse(struct module_qstate* qstate, struct iter_qstate* iq,
|
||||
orig_empty_nodata_found = iq->empty_nodata_found;
|
||||
type = response_type_from_server(
|
||||
(int)((iq->chase_flags&BIT_RD) || iq->chase_to_rd),
|
||||
iq->response, &iq->qinfo_out, iq->dp, &iq->empty_nodata_found);
|
||||
iq->response, &iq->qinfo_out, iq->dp, &iq->empty_nodata_found,
|
||||
iq->msg_lame_empty, iq->msg_lame_referral);
|
||||
iq->chase_to_rd = 0;
|
||||
/* remove TC flag, if this is erroneously set by TCP upstream */
|
||||
iq->response->rep->flags &= ~BIT_TC;
|
||||
@@ -3230,8 +3259,19 @@ processQueryResponse(struct module_qstate* qstate, struct iter_qstate* iq,
|
||||
} else iter_scrub_ds(iq->response, NULL, NULL);
|
||||
if(type == RESPONSE_TYPE_THROWAWAY &&
|
||||
FLAGS_GET_RCODE(iq->response->rep->flags) == LDNS_RCODE_YXDOMAIN) {
|
||||
/* YXDOMAIN is a permanent error, no need to retry */
|
||||
type = RESPONSE_TYPE_ANSWER;
|
||||
/* YXDOMAIN is a permanent error for DNAME expansion overflow
|
||||
* (RFC 6672 Section 2.2). Only accept if the response
|
||||
* contains a DNAME record in the answer section; otherwise
|
||||
* treat as invalid, to make sure the authoritative answer
|
||||
* make sense. */
|
||||
size_t i;
|
||||
for(i=0; i<iq->response->rep->an_numrrsets; i++) {
|
||||
if(ntohs(iq->response->rep->rrsets[i]->rk.type)
|
||||
== LDNS_RR_TYPE_DNAME) {
|
||||
type = RESPONSE_TYPE_ANSWER;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
if(type == RESPONSE_TYPE_CNAME)
|
||||
origtypecname = 1;
|
||||
@@ -3247,13 +3287,19 @@ processQueryResponse(struct module_qstate* qstate, struct iter_qstate* iq,
|
||||
}
|
||||
}
|
||||
if(type == RESPONSE_TYPE_CNAME &&
|
||||
iq->qchase.qtype == LDNS_RR_TYPE_CNAME &&
|
||||
(iq->qchase.qtype == LDNS_RR_TYPE_CNAME ||
|
||||
iq->qchase.qtype == LDNS_RR_TYPE_ANY) &&
|
||||
iq->minimisation_state == MINIMISE_STATE &&
|
||||
query_dname_compare(iq->qchase.qname, iq->qinfo_out.qname) == 0) {
|
||||
/* The minimised query for full QTYPE and hidden QTYPE can be
|
||||
* classified as CNAME response type, even when the original
|
||||
* QTYPE=CNAME. This should be treated as answer response type.
|
||||
*/
|
||||
/* For QTYPE=ANY, it is also considered the response, that
|
||||
* is what the classifier would say, if it saw qtype ANY,
|
||||
* and this same response was returned for that. The response
|
||||
* can already be treated as such an answer, without having
|
||||
* to send another query with a new qtype. */
|
||||
type = RESPONSE_TYPE_ANSWER;
|
||||
}
|
||||
|
||||
@@ -3421,7 +3467,14 @@ processQueryResponse(struct module_qstate* qstate, struct iter_qstate* iq,
|
||||
iq->deleg_msg = iq->response;
|
||||
/* Keep current delegation point for label comparison */
|
||||
old_dp = iq->dp;
|
||||
iq->dp = delegpt_from_message(iq->response, qstate->region);
|
||||
/* A referral reply is "pleasant", refund the
|
||||
* parent dp's rate charge before descending to the child. */
|
||||
if(iq->ratelimit_incremented)
|
||||
infra_ratelimit_dec(qstate->env->infra_cache,
|
||||
old_dp->name, old_dp->namelen,
|
||||
*qstate->env->now);
|
||||
iq->dp = delegpt_from_message(iq->response, qstate->region,
|
||||
deleg_port_number(qstate->env));
|
||||
if (qstate->env->cfg->qname_minimisation)
|
||||
iq->minimisation_state = INIT_MINIMISE_STATE;
|
||||
if(!iq->dp) {
|
||||
@@ -3510,6 +3563,15 @@ processQueryResponse(struct module_qstate* qstate, struct iter_qstate* iq,
|
||||
iq->num_target_queries = 0;
|
||||
return processDSNSFind(qstate, iq, id);
|
||||
}
|
||||
if(iq->minimisation_state == MINIMISE_STATE &&
|
||||
query_dname_compare(iq->qchase.qname,
|
||||
iq->qinfo_out.qname) != 0) {
|
||||
verbose(VERB_ALGO, "continue query minimisation, "
|
||||
"downwards, after CNAME response for "
|
||||
"intermediate label");
|
||||
/* continue query minimisation, downwards */
|
||||
return next_state(iq, QUERYTARGETS_STATE);
|
||||
}
|
||||
/* Process the CNAME response. */
|
||||
if(!handle_cname_response(qstate, iq, iq->response,
|
||||
&sname, &snamelen)) {
|
||||
@@ -3572,10 +3634,7 @@ processQueryResponse(struct module_qstate* qstate, struct iter_qstate* iq,
|
||||
iq->auth_zone_response = 0;
|
||||
iq->sent_count = 0;
|
||||
iq->dp_target_count = 0;
|
||||
if(iq->minimisation_state != MINIMISE_STATE)
|
||||
/* Only count as query restart when it is not an extra
|
||||
* query as result of qname minimisation. */
|
||||
iq->query_restart_count++;
|
||||
iq->query_restart_count++;
|
||||
if(qstate->env->cfg->qname_minimisation)
|
||||
iq->minimisation_state = INIT_MINIMISE_STATE;
|
||||
|
||||
@@ -3598,7 +3657,7 @@ processQueryResponse(struct module_qstate* qstate, struct iter_qstate* iq,
|
||||
return next_state(iq, INIT_REQUEST_STATE);
|
||||
} else if(type == RESPONSE_TYPE_LAME) {
|
||||
/* Cache the LAMEness. */
|
||||
verbose(VERB_DETAIL, "query response was %sLAME",
|
||||
verbose(VERB_DETAIL, "query response was categorized as %sLAME",
|
||||
dnsseclame?"DNSSEC ":"");
|
||||
if(!dname_subdomain_c(iq->qchase.qname, iq->dp->name)) {
|
||||
log_err("mark lame: mismatch in qname and dpname");
|
||||
@@ -3637,7 +3696,7 @@ processQueryResponse(struct module_qstate* qstate, struct iter_qstate* iq,
|
||||
* In this case, the event is just sent directly back to
|
||||
* the QUERYTARGETS_STATE without resetting anything,
|
||||
* because, clearly, the next target must be tried. */
|
||||
verbose(VERB_DETAIL, "query response was THROWAWAY");
|
||||
verbose(VERB_DETAIL, "query response was categorized as THROWAWAY");
|
||||
} else {
|
||||
log_warn("A query response came back with an unknown type: %d",
|
||||
(int)type);
|
||||
@@ -3692,7 +3751,8 @@ prime_supers(struct module_qstate* qstate, int id, struct module_qstate* forq)
|
||||
log_assert(qstate->is_priming || foriq->wait_priming_stub);
|
||||
log_assert(qstate->return_rcode == LDNS_RCODE_NOERROR);
|
||||
/* Convert our response to a delegation point */
|
||||
dp = delegpt_from_message(qstate->return_msg, forq->region);
|
||||
dp = delegpt_from_message(qstate->return_msg, forq->region,
|
||||
deleg_port_number(forq->env));
|
||||
if(!dp) {
|
||||
/* if there is no convertible delegation point, then
|
||||
* the ANSWER type was (presumably) a negative answer. */
|
||||
@@ -3743,7 +3803,8 @@ processPrimeResponse(struct module_qstate* qstate, int id)
|
||||
iq->response->rep->flags &= ~(BIT_RD|BIT_RA); /* ignore rec-lame */
|
||||
type = response_type_from_server(
|
||||
(int)((iq->chase_flags&BIT_RD) || iq->chase_to_rd),
|
||||
iq->response, &iq->qchase, iq->dp, NULL);
|
||||
iq->response, &iq->qchase, iq->dp, NULL, iq->msg_lame_empty,
|
||||
iq->msg_lame_referral);
|
||||
if(type == RESPONSE_TYPE_ANSWER) {
|
||||
qstate->return_rcode = LDNS_RCODE_NOERROR;
|
||||
qstate->return_msg = iq->response;
|
||||
@@ -3862,7 +3923,7 @@ processTargetResponse(struct module_qstate* qstate, int id,
|
||||
/* no new addresses, increase the nxns counter, like
|
||||
* this could be a list of wildcards with no new
|
||||
* addresses */
|
||||
target_count_increase_nx(foriq, 1);
|
||||
target_count_increase_nx(qstate, foriq, 1);
|
||||
}
|
||||
verbose(VERB_ALGO, "added target response");
|
||||
delegpt_log(VERB_ALGO, foriq->dp);
|
||||
@@ -3874,7 +3935,7 @@ processTargetResponse(struct module_qstate* qstate, int id,
|
||||
dpns->resolved = 1; /* fail the target */
|
||||
/* do not count cached answers */
|
||||
if(qstate->reply_origin && qstate->reply_origin->len != 0) {
|
||||
target_count_increase_nx(foriq, 1);
|
||||
target_count_increase_nx(qstate, foriq, 1);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -3907,7 +3968,8 @@ processDSNSResponse(struct module_qstate* qstate, int id,
|
||||
|
||||
/* else, store as DP and continue at querytargets */
|
||||
foriq->state = QUERYTARGETS_STATE;
|
||||
foriq->dp = delegpt_from_message(qstate->return_msg, forq->region);
|
||||
foriq->dp = delegpt_from_message(qstate->return_msg, forq->region,
|
||||
deleg_port_number(forq->env));
|
||||
if(!foriq->dp) {
|
||||
log_err("out of memory in dsns dp alloc");
|
||||
errinf(qstate, "malloc failure, in DS search");
|
||||
@@ -3956,7 +4018,7 @@ processClassResponse(struct module_qstate* qstate, int id,
|
||||
/* if there are records, copy RCODE */
|
||||
/* lower sec_state if this message is lower */
|
||||
if(from->rep->rrset_count != 0) {
|
||||
size_t n = from->rep->rrset_count+to->rep->rrset_count;
|
||||
size_t i, n = from->rep->rrset_count+to->rep->rrset_count;
|
||||
struct ub_packed_rrset_key** dest, **d;
|
||||
/* copy appropriate rcode */
|
||||
to->rep->flags = from->rep->flags;
|
||||
@@ -3978,24 +4040,49 @@ processClassResponse(struct module_qstate* qstate, int id,
|
||||
memcpy(dest, to->rep->rrsets, to->rep->an_numrrsets
|
||||
* sizeof(dest[0]));
|
||||
dest += to->rep->an_numrrsets;
|
||||
memcpy(dest, from->rep->rrsets, from->rep->an_numrrsets
|
||||
* sizeof(dest[0]));
|
||||
for(i=0; i<from->rep->an_numrrsets; i++) {
|
||||
dest[i] = packed_rrset_copy_region(
|
||||
from->rep->rrsets[i], forq->region, 0);
|
||||
if(!dest[i]) {
|
||||
log_err("malloc failed in collect ANY");
|
||||
foriq->state = FINISHED_STATE;
|
||||
return;
|
||||
}
|
||||
}
|
||||
dest += from->rep->an_numrrsets;
|
||||
/* copy NS */
|
||||
memcpy(dest, to->rep->rrsets+to->rep->an_numrrsets,
|
||||
to->rep->ns_numrrsets * sizeof(dest[0]));
|
||||
dest += to->rep->ns_numrrsets;
|
||||
memcpy(dest, from->rep->rrsets+from->rep->an_numrrsets,
|
||||
from->rep->ns_numrrsets * sizeof(dest[0]));
|
||||
for(i=0; i<from->rep->ns_numrrsets; i++) {
|
||||
dest[i] = packed_rrset_copy_region(
|
||||
from->rep->rrsets[
|
||||
from->rep->an_numrrsets+i],
|
||||
forq->region, 0);
|
||||
if(!dest[i]) {
|
||||
log_err("malloc failed in collect ANY");
|
||||
foriq->state = FINISHED_STATE;
|
||||
return;
|
||||
}
|
||||
}
|
||||
dest += from->rep->ns_numrrsets;
|
||||
/* copy AR */
|
||||
memcpy(dest, to->rep->rrsets+to->rep->an_numrrsets+
|
||||
to->rep->ns_numrrsets,
|
||||
to->rep->ar_numrrsets * sizeof(dest[0]));
|
||||
dest += to->rep->ar_numrrsets;
|
||||
memcpy(dest, from->rep->rrsets+from->rep->an_numrrsets+
|
||||
from->rep->ns_numrrsets,
|
||||
from->rep->ar_numrrsets * sizeof(dest[0]));
|
||||
for(i=0; i<from->rep->ar_numrrsets; i++) {
|
||||
dest[i] = packed_rrset_copy_region(
|
||||
from->rep->rrsets[
|
||||
from->rep->an_numrrsets+
|
||||
from->rep->ns_numrrsets+i],
|
||||
forq->region, 0);
|
||||
if(!dest[i]) {
|
||||
log_err("malloc failed in collect ANY");
|
||||
foriq->state = FINISHED_STATE;
|
||||
return;
|
||||
}
|
||||
}
|
||||
/* update counts */
|
||||
to->rep->rrsets = d;
|
||||
to->rep->an_numrrsets += from->rep->an_numrrsets;
|
||||
@@ -4099,6 +4186,7 @@ processFinished(struct module_qstate* qstate, struct iter_qstate* iq,
|
||||
iter_store_parentside_neg(qstate->env, &qstate->qinfo,
|
||||
iq->deleg_msg?iq->deleg_msg->rep:
|
||||
(iq->response?iq->response->rep:NULL));
|
||||
target_count_store(qstate, iq);
|
||||
if(!iq->response) {
|
||||
verbose(VERB_ALGO, "No response is set, servfail");
|
||||
errinf(qstate, "(no response found at query finish)");
|
||||
@@ -4147,7 +4235,7 @@ processFinished(struct module_qstate* qstate, struct iter_qstate* iq,
|
||||
/* store message with the finished prepended items,
|
||||
* but only if we did recursion. The nonrecursion referral
|
||||
* from cache does not need to be stored in the msg cache. */
|
||||
if(!qstate->no_cache_store && qstate->query_flags&BIT_RD) {
|
||||
if(!qstate->no_cache_store && (qstate->query_flags&BIT_RD)) {
|
||||
iter_dns_store(qstate->env, &qstate->qinfo,
|
||||
iq->response->rep, 0, qstate->prefetch_leeway,
|
||||
iq->dp&&iq->dp->has_parent_side_NS,
|
||||
@@ -4352,7 +4440,10 @@ process_response(struct module_qstate* qstate, struct iter_qstate* iq,
|
||||
|
||||
/* normalize and sanitize: easy to delete items from linked lists */
|
||||
if(!scrub_message(pkt, prs, &iq->qinfo_out, iq->dp->name,
|
||||
qstate->env->scratch, qstate->env, qstate, ie)) {
|
||||
qstate->env->scratch, qstate->env, qstate, ie,
|
||||
&iq->msg_lame_empty, &iq->msg_lame_referral,
|
||||
(int)((iq->chase_flags&BIT_RD) || iq->chase_to_rd)
|
||||
)) {
|
||||
/* if 0x20 enabled, start fallback, but we have no message */
|
||||
if(event == module_event_capsfail && !iq->caps_fallback) {
|
||||
iq->caps_fallback = 1;
|
||||
@@ -4514,6 +4605,7 @@ iter_clear(struct module_qstate* qstate, int id)
|
||||
iq = (struct iter_qstate*)qstate->minfo[id];
|
||||
if(iq) {
|
||||
outbound_list_clear(&iq->outlist);
|
||||
target_count_store(qstate, iq);
|
||||
if(iq->target_count && --iq->target_count[TARGET_COUNT_REF] == 0) {
|
||||
free(iq->target_count);
|
||||
if(*iq->nxns_dp) free(*iq->nxns_dp);
|
||||
|
||||
@@ -104,6 +104,11 @@ extern int BLACKLIST_PENALTY;
|
||||
#define RTT_BAND 400
|
||||
/** Number of retries for empty nodata packets before it is accepted. */
|
||||
#define EMPTY_NODATA_RETRY_COUNT 2
|
||||
/** max label-strip iterations in DSNS_FIND_STATE (RFC 4035 4.2 parent-NS
|
||||
* search) before giving up; bounds upstream NS sends per client DS.
|
||||
* Means the max number of labels in grandchild to the grandparent zone that
|
||||
* are co-hosted. */
|
||||
#define MAX_DSNS_FIND_COUNT 20
|
||||
|
||||
/**
|
||||
* Iterator global state for nat64.
|
||||
@@ -375,6 +380,10 @@ struct iter_qstate {
|
||||
/** if true, already tested for ratelimiting and passed the test */
|
||||
int ratelimit_ok;
|
||||
|
||||
/** If the last query, that may be a referral, incremented the
|
||||
* ratelimit counter. */
|
||||
int ratelimit_incremented;
|
||||
|
||||
/**
|
||||
* The query must store NS records from referrals as parentside RRs
|
||||
* Enabled once it hits resolution problems, to throttle retries.
|
||||
@@ -399,6 +408,8 @@ struct iter_qstate {
|
||||
uint8_t* dsns_point;
|
||||
/** length of the dname in dsns_point */
|
||||
size_t dsns_point_len;
|
||||
/** number of label-strip iterations performed in DSNS_FIND_STATE */
|
||||
int dsns_count;
|
||||
|
||||
/**
|
||||
* expected dnssec information for this iteration step.
|
||||
@@ -434,6 +445,13 @@ struct iter_qstate {
|
||||
* already so that it is accepted later. */
|
||||
int empty_nodata_found;
|
||||
|
||||
/** Store if the answer was empty, but lame, before it became empty.*/
|
||||
int msg_lame_empty;
|
||||
|
||||
/** Store if the answer was a referral, to self, before scrub. So the
|
||||
* it is not some sort of answer. */
|
||||
int msg_lame_referral;
|
||||
|
||||
/** list of pending queries to authoritative servers. */
|
||||
struct outbound_list outlist;
|
||||
|
||||
|
||||
@@ -167,6 +167,8 @@ struct ctx_query {
|
||||
ub_event_callback_type cb_event;
|
||||
/** for async query, the callback user arg */
|
||||
void* cb_arg;
|
||||
/** for async query the unique info */
|
||||
void* unique_info;
|
||||
|
||||
/** answer message, result from resolver lookup. */
|
||||
uint8_t* msg;
|
||||
|
||||
@@ -571,6 +571,8 @@ ub_ctx_async(struct ub_ctx* ctx, int dothread)
|
||||
int
|
||||
ub_poll(struct ub_ctx* ctx)
|
||||
{
|
||||
if(!ctx || ctx->event_base)
|
||||
return UB_INITFAIL;
|
||||
/* no need to hold lock while testing for readability. */
|
||||
return tube_poll(ctx->rr_pipe);
|
||||
}
|
||||
@@ -578,6 +580,8 @@ ub_poll(struct ub_ctx* ctx)
|
||||
int
|
||||
ub_fd(struct ub_ctx* ctx)
|
||||
{
|
||||
if(!ctx || ctx->event_base)
|
||||
return -1;
|
||||
return tube_read_fd(ctx->rr_pipe);
|
||||
}
|
||||
|
||||
@@ -672,6 +676,8 @@ ub_process(struct ub_ctx* ctx)
|
||||
int r;
|
||||
uint8_t* msg;
|
||||
uint32_t len;
|
||||
if(!ctx || ctx->event_base)
|
||||
return UB_INITFAIL;
|
||||
while(1) {
|
||||
msg = NULL;
|
||||
lock_basic_lock(&ctx->rrpipe_lock);
|
||||
@@ -700,6 +706,8 @@ ub_wait(struct ub_ctx* ctx)
|
||||
int r;
|
||||
uint8_t* msg;
|
||||
uint32_t len;
|
||||
if(!ctx || ctx->event_base)
|
||||
return UB_INITFAIL;
|
||||
/* this is basically the same loop as _process(), but with changes.
|
||||
* holds the rrpipe lock and waits with tube_wait */
|
||||
while(1) {
|
||||
@@ -837,6 +845,8 @@ ub_resolve_async(struct ub_ctx* ctx, const char* name, int rrtype,
|
||||
struct ctx_query* q;
|
||||
uint8_t* msg = NULL;
|
||||
uint32_t len = 0;
|
||||
if(!ctx || ctx->event_base)
|
||||
return UB_INITFAIL;
|
||||
|
||||
if(async_id)
|
||||
*async_id = 0;
|
||||
@@ -1467,8 +1477,15 @@ ub_ctx_set_event(struct ub_ctx* ctx, struct event_base* base) {
|
||||
|
||||
lock_basic_lock(&ctx->cfglock);
|
||||
/* destroy the current worker - safe to pass in NULL */
|
||||
|
||||
/* Unlock the cfglock during libworker_delete_event, since it
|
||||
* calls context_release_alloc, that wants to lock cfglock again.
|
||||
* Since the event base is used from one thread, the one that
|
||||
* called this function, it is safe to do so. */
|
||||
lock_basic_unlock(&ctx->cfglock);
|
||||
libworker_delete_event(ctx->event_worker);
|
||||
ctx->event_worker = NULL;
|
||||
lock_basic_lock(&ctx->cfglock);
|
||||
new_base = ub_libevent_event_base(base);
|
||||
if (new_base)
|
||||
ctx->event_base = new_base;
|
||||
|
||||
+31
-14
@@ -105,6 +105,7 @@ libworker_delete_env(struct libworker* w)
|
||||
SSL_CTX_free(w->sslctx);
|
||||
#endif
|
||||
outside_network_delete(w->back);
|
||||
shared_ports_delete(w->shared_ports);
|
||||
}
|
||||
|
||||
/** delete libworker struct */
|
||||
@@ -219,17 +220,25 @@ libworker_setup(struct ub_ctx* ctx, int is_bg, struct ub_event_base* eb)
|
||||
libworker_delete(w);
|
||||
return NULL;
|
||||
}
|
||||
if(!(w->shared_ports = shared_ports_create(cfg->out_ifs,
|
||||
cfg->num_out_ifs, cfg->do_ip4, cfg->do_ip6, ports, numports))) {
|
||||
if(!w->is_bg || w->is_bg_thread) {
|
||||
lock_basic_unlock(&ctx->cfglock);
|
||||
}
|
||||
libworker_delete(w);
|
||||
return NULL;
|
||||
}
|
||||
w->back = outside_network_create(w->base, cfg->msg_buffer_size,
|
||||
(size_t)cfg->outgoing_num_ports, cfg->out_ifs,
|
||||
cfg->num_out_ifs, cfg->do_ip4, cfg->do_ip6,
|
||||
cfg->do_tcp?cfg->outgoing_num_tcp:0, cfg->ip_dscp,
|
||||
w->env->infra_cache, w->env->rnd, cfg->use_caps_bits_for_id,
|
||||
ports, numports, cfg->unwanted_threshold,
|
||||
cfg->unwanted_threshold,
|
||||
cfg->outgoing_tcp_mss, &libworker_alloc_cleanup, w,
|
||||
cfg->do_udp || cfg->udp_upstream_without_downstream, w->sslctx,
|
||||
cfg->delay_close, cfg->tls_use_sni, NULL, cfg->udp_connect,
|
||||
cfg->max_reuse_tcp_queries, cfg->tcp_reuse_timeout,
|
||||
cfg->tcp_auth_query_timeout);
|
||||
cfg->tcp_auth_query_timeout, w->shared_ports);
|
||||
w->env->outnet = w->back;
|
||||
if(!w->is_bg || w->is_bg_thread) {
|
||||
lock_basic_unlock(&ctx->cfglock);
|
||||
@@ -630,8 +639,9 @@ int libworker_fg(struct ub_ctx* ctx, struct ctx_query* q)
|
||||
free(qinfo.qname);
|
||||
return UB_NOERROR;
|
||||
}
|
||||
if(ctx->env->auth_zones && auth_zones_answer(ctx->env->auth_zones,
|
||||
w->env, &qinfo, &edns, NULL, w->back->udp_buff, w->env->scratch)) {
|
||||
if(ctx->env->auth_zones && auth_zones_downstream_answer(
|
||||
ctx->env->auth_zones, w->env, &qinfo, &edns, NULL,
|
||||
w->back->udp_buff, w->env->scratch)) {
|
||||
regional_free_all(w->env->scratch);
|
||||
libworker_fillup_fg(q, LDNS_RCODE_NOERROR,
|
||||
w->back->udp_buff, sec_status_insecure, NULL, 0);
|
||||
@@ -641,7 +651,8 @@ int libworker_fg(struct ub_ctx* ctx, struct ctx_query* q)
|
||||
}
|
||||
/* process new query */
|
||||
if(!mesh_new_callback(w->env->mesh, &qinfo, qflags, &edns,
|
||||
w->back->udp_buff, qid, libworker_fg_done_cb, q, 0)) {
|
||||
w->back->udp_buff, qid, libworker_fg_done_cb, q, 0,
|
||||
&q->unique_info)) {
|
||||
free(qinfo.qname);
|
||||
return UB_NOMEM;
|
||||
}
|
||||
@@ -709,8 +720,9 @@ int libworker_attach_mesh(struct ub_ctx* ctx, struct ctx_query* q,
|
||||
w->back->udp_buff, sec_status_insecure, NULL, 0);
|
||||
return UB_NOERROR;
|
||||
}
|
||||
if(ctx->env->auth_zones && auth_zones_answer(ctx->env->auth_zones,
|
||||
w->env, &qinfo, &edns, NULL, w->back->udp_buff, w->env->scratch)) {
|
||||
if(ctx->env->auth_zones && auth_zones_downstream_answer(
|
||||
ctx->env->auth_zones, w->env, &qinfo, &edns, NULL,
|
||||
w->back->udp_buff, w->env->scratch)) {
|
||||
regional_free_all(w->env->scratch);
|
||||
free(qinfo.qname);
|
||||
libworker_event_done_cb(q, LDNS_RCODE_NOERROR,
|
||||
@@ -721,7 +733,8 @@ int libworker_attach_mesh(struct ub_ctx* ctx, struct ctx_query* q,
|
||||
if(async_id)
|
||||
*async_id = q->querynum;
|
||||
if(!mesh_new_callback(w->env->mesh, &qinfo, qflags, &edns,
|
||||
w->back->udp_buff, qid, libworker_event_done_cb, q, 0)) {
|
||||
w->back->udp_buff, qid, libworker_event_done_cb, q, 0,
|
||||
&q->unique_info)) {
|
||||
free(qinfo.qname);
|
||||
return UB_NOMEM;
|
||||
}
|
||||
@@ -847,8 +860,9 @@ handle_newq(struct libworker* w, uint8_t* buf, uint32_t len)
|
||||
free(qinfo.qname);
|
||||
return;
|
||||
}
|
||||
if(w->ctx->env->auth_zones && auth_zones_answer(w->ctx->env->auth_zones,
|
||||
w->env, &qinfo, &edns, NULL, w->back->udp_buff, w->env->scratch)) {
|
||||
if(w->ctx->env->auth_zones && auth_zones_downstream_answer(
|
||||
w->ctx->env->auth_zones, w->env, &qinfo, &edns, NULL,
|
||||
w->back->udp_buff, w->env->scratch)) {
|
||||
regional_free_all(w->env->scratch);
|
||||
q->msg_security = sec_status_insecure;
|
||||
add_bg_result(w, q, w->back->udp_buff, UB_NOERROR, NULL, 0);
|
||||
@@ -858,7 +872,8 @@ handle_newq(struct libworker* w, uint8_t* buf, uint32_t len)
|
||||
q->w = w;
|
||||
/* process new query */
|
||||
if(!mesh_new_callback(w->env->mesh, &qinfo, qflags, &edns,
|
||||
w->back->udp_buff, qid, libworker_bg_done_cb, q, 0)) {
|
||||
w->back->udp_buff, qid, libworker_bg_done_cb, q, 0,
|
||||
&q->unique_info)) {
|
||||
add_bg_result(w, q, NULL, UB_NOMEM, NULL, 0);
|
||||
}
|
||||
free(qinfo.qname);
|
||||
@@ -876,7 +891,8 @@ struct outbound_entry* libworker_send_query(struct query_info* qinfo,
|
||||
int check_ratelimit,
|
||||
struct sockaddr_storage* addr, socklen_t addrlen, uint8_t* zone,
|
||||
size_t zonelen, int tcp_upstream, int ssl_upstream, char* tls_auth_name,
|
||||
struct module_qstate* q, int* was_ratelimited)
|
||||
struct module_qstate* q, int* was_ratelimited,
|
||||
int* ratelimit_incremented)
|
||||
{
|
||||
struct libworker* w = (struct libworker*)q->env->worker;
|
||||
struct outbound_entry* e = (struct outbound_entry*)regional_alloc(
|
||||
@@ -888,7 +904,7 @@ struct outbound_entry* libworker_send_query(struct query_info* qinfo,
|
||||
want_dnssec, nocaps, check_ratelimit, tcp_upstream, ssl_upstream,
|
||||
tls_auth_name, addr, addrlen, zone, zonelen, q,
|
||||
libworker_handle_service_reply, e, w->back->udp_buff, q->env,
|
||||
was_ratelimited);
|
||||
was_ratelimited, ratelimit_incremented);
|
||||
if(!e->qsent) {
|
||||
return NULL;
|
||||
}
|
||||
@@ -973,7 +989,8 @@ struct outbound_entry* worker_send_query(struct query_info* ATTR_UNUSED(qinfo),
|
||||
struct sockaddr_storage* ATTR_UNUSED(addr), socklen_t ATTR_UNUSED(addrlen),
|
||||
uint8_t* ATTR_UNUSED(zone), size_t ATTR_UNUSED(zonelen), int ATTR_UNUSED(tcp_upstream),
|
||||
int ATTR_UNUSED(ssl_upstream), char* ATTR_UNUSED(tls_auth_name),
|
||||
struct module_qstate* ATTR_UNUSED(q), int* ATTR_UNUSED(was_ratelimited))
|
||||
struct module_qstate* ATTR_UNUSED(q), int* ATTR_UNUSED(was_ratelimited),
|
||||
int* ATTR_UNUSED(ratelimit_incremented))
|
||||
{
|
||||
log_assert(0);
|
||||
return 0;
|
||||
|
||||
@@ -60,6 +60,7 @@ struct tube;
|
||||
struct sldns_buffer;
|
||||
struct ub_event_base;
|
||||
struct query_info;
|
||||
struct shared_ports;
|
||||
|
||||
/**
|
||||
* The library-worker status structure
|
||||
@@ -84,6 +85,8 @@ struct libworker {
|
||||
struct comm_base* base;
|
||||
/** the backside outside network interface to the auth servers */
|
||||
struct outside_network* back;
|
||||
/** shared ports structure */
|
||||
struct shared_ports* shared_ports;
|
||||
/** random() table for this worker. */
|
||||
struct ub_randstate* rndstate;
|
||||
/** sslcontext for SSL wrapped DNS over TCP queries */
|
||||
|
||||
@@ -853,7 +853,7 @@ Result: ['74.125.43.147', '74.125.43.99', '74.125.43.103', '74.125.43.104']
|
||||
%{
|
||||
//printf("resolve_start(%lX)\n",(long unsigned int)arg1);
|
||||
Py_BEGIN_ALLOW_THREADS
|
||||
$function
|
||||
$action
|
||||
Py_END_ALLOW_THREADS
|
||||
//printf("resolve_stop()\n");
|
||||
%}
|
||||
|
||||
@@ -0,0 +1,65 @@
|
||||
/*
|
||||
* libunbound/remote.h - prototypes for remote control methods.
|
||||
*
|
||||
* Copyright (c) 2026, NLnet Labs. All rights reserved.
|
||||
*
|
||||
* This software is open source.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
*
|
||||
* Redistributions of source code must retain the above copyright notice,
|
||||
* this list of conditions and the following disclaimer.
|
||||
*
|
||||
* Redistributions in binary form must reproduce the above copyright notice,
|
||||
* this list of conditions and the following disclaimer in the documentation
|
||||
* and/or other materials provided with the distribution.
|
||||
*
|
||||
* Neither the name of the NLNET LABS nor the names of its contributors may
|
||||
* be used to endorse or promote products derived from this software without
|
||||
* specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
* HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED
|
||||
* TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
|
||||
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
|
||||
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
||||
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
/**
|
||||
* \file
|
||||
*
|
||||
* This file declares the methods that must be implemented to use the
|
||||
* remote control service.
|
||||
*/
|
||||
|
||||
#ifndef LIBUNBOUND_REMOTE_H
|
||||
#define LIBUNBOUND_REMOTE_H
|
||||
|
||||
struct comm_reply;
|
||||
struct comm_point;
|
||||
|
||||
/** fast reload thread commands to remote service thread event callback */
|
||||
void fast_reload_service_cb(int fd, short bits, void* arg);
|
||||
|
||||
/** fast reload callback for the remote control client connection */
|
||||
int fast_reload_client_callback(struct comm_point* c, void* arg, int err,
|
||||
struct comm_reply* rep);
|
||||
|
||||
/** handle remote control accept callbacks */
|
||||
int remote_accept_callback(struct comm_point*, void*, int, struct comm_reply*);
|
||||
|
||||
/** handle remote control data callbacks */
|
||||
int remote_control_callback(struct comm_point*, void*, int, struct comm_reply*);
|
||||
|
||||
/** routine to printout option values over SSL */
|
||||
void remote_get_opt_ssl(char* line, void* arg);
|
||||
|
||||
#endif /* LIBUNBOUND_REMOTE_H */
|
||||
@@ -772,6 +772,8 @@ struct ub_server_stats {
|
||||
long long ans_bogus;
|
||||
/** rrsets marked bogus by validator */
|
||||
long long rrset_bogus;
|
||||
/** number of signature validation operations performed by validator */
|
||||
long long val_ops;
|
||||
/** number of queries that have been ratelimited by domain recursion. */
|
||||
long long queries_ratelimited;
|
||||
/** unwanted traffic received on server-facing ports */
|
||||
@@ -851,6 +853,8 @@ struct ub_server_stats {
|
||||
long long qquic;
|
||||
/** number of queries removed due to discard-timeout */
|
||||
long long num_queries_discard_timeout;
|
||||
/** number of queries removed due to replyaddr limit */
|
||||
long long num_queries_replyaddr_limit;
|
||||
/** number of queries removed due to wait-limit */
|
||||
long long num_queries_wait_limit;
|
||||
/** number of dns error reports generated */
|
||||
@@ -870,6 +874,8 @@ struct ub_stats_info {
|
||||
long long mesh_num_states;
|
||||
/** mesh stats: current number of reply (user) states */
|
||||
long long mesh_num_reply_states;
|
||||
/** mesh stats: current number of reply entries */
|
||||
long long mesh_num_reply_addrs;
|
||||
/** mesh stats: number of reply states overwritten with a new one */
|
||||
long long mesh_jostled;
|
||||
/** mesh stats: number of incoming queries dropped */
|
||||
|
||||
+8
-11
@@ -70,6 +70,8 @@ struct query_info;
|
||||
* @param q: which query state to reactivate upon return.
|
||||
* @param was_ratelimited: it will signal back if the query failed to pass the
|
||||
* ratelimit check.
|
||||
* @param ratelimit_incremented: set to true if the ratelimit counter
|
||||
* was increased.
|
||||
* @return: false on failure (memory or socket related). no query was
|
||||
* sent.
|
||||
*/
|
||||
@@ -78,7 +80,8 @@ struct outbound_entry* libworker_send_query(struct query_info* qinfo,
|
||||
int check_ratelimit,
|
||||
struct sockaddr_storage* addr, socklen_t addrlen, uint8_t* zone,
|
||||
size_t zonelen, int tcp_upstream, int ssl_upstream, char* tls_auth_name,
|
||||
struct module_qstate* q, int* was_ratelimited);
|
||||
struct module_qstate* q, int* was_ratelimited,
|
||||
int* ratelimit_incremented);
|
||||
|
||||
/** process incoming serviced query replies from the network */
|
||||
int libworker_handle_service_reply(struct comm_point* c, void* arg, int error,
|
||||
@@ -126,6 +129,8 @@ void worker_sighandler(int sig, void* arg);
|
||||
* @param q: which query state to reactivate upon return.
|
||||
* @param was_ratelimited: it will signal back if the query failed to pass the
|
||||
* ratelimit check.
|
||||
* @param ratelimit_incremented: set to true if the ratelimit counter
|
||||
* was increased.
|
||||
* @return: false on failure (memory or socket related). no query was
|
||||
* sent.
|
||||
*/
|
||||
@@ -134,7 +139,8 @@ struct outbound_entry* worker_send_query(struct query_info* qinfo,
|
||||
int check_ratelimit,
|
||||
struct sockaddr_storage* addr, socklen_t addrlen, uint8_t* zone,
|
||||
size_t zonelen, int tcp_upstream, int ssl_upstream, char* tls_auth_name,
|
||||
struct module_qstate* q, int* was_ratelimited);
|
||||
struct module_qstate* q, int* was_ratelimited,
|
||||
int* ratelimit_incremented);
|
||||
|
||||
/**
|
||||
* process control messages from the main thread. Frees the control
|
||||
@@ -171,13 +177,4 @@ void worker_start_accept(void* arg);
|
||||
/** stop accept callback handler */
|
||||
void worker_stop_accept(void* arg);
|
||||
|
||||
/** handle remote control accept callbacks */
|
||||
int remote_accept_callback(struct comm_point*, void*, int, struct comm_reply*);
|
||||
|
||||
/** handle remote control data callbacks */
|
||||
int remote_control_callback(struct comm_point*, void*, int, struct comm_reply*);
|
||||
|
||||
/** routine to printout option values over SSL */
|
||||
void remote_get_opt_ssl(char* line, void* arg);
|
||||
|
||||
#endif /* LIBUNBOUND_WORKER_H */
|
||||
|
||||
+18
-3
@@ -59,7 +59,7 @@ Generate a distribution tar file for unbound.
|
||||
-wxp expat.xx.tar.gz Also build expat from tarball for windows dist.
|
||||
-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
|
||||
they are used right away. Useful when debugging windows
|
||||
builds.
|
||||
-w32 32bit windows compile.
|
||||
-w ... Build windows binary dist. last args passed to configure.
|
||||
@@ -440,6 +440,7 @@ if [ "$DOWIN" = "yes" ]; then
|
||||
autoheader -f || error_cleanup "Autoheader failed."
|
||||
rm -r autom4te* || echo "ignored"
|
||||
rm -f config.h.in~ || echo "ignore absence of config.h.in~ file."
|
||||
rm -f configure~ || echo "ignore absence of configure~ file."
|
||||
fi
|
||||
|
||||
if test "`uname`" = "Linux"; then
|
||||
@@ -465,9 +466,13 @@ if [ "$DOWIN" = "yes" ]; then
|
||||
|| error_cleanup "Could not configure"
|
||||
set +x
|
||||
else
|
||||
# Add -l:libssp:a to statically link libssp if possible.
|
||||
# Put it at the end of LIBS, to satisfy also linked in
|
||||
# dependencies.
|
||||
set -x
|
||||
$configure --enable-debug --enable-static-exe --disable-flto --disable-gost $* $cross_flag \
|
||||
|| error_cleanup "Could not configure"
|
||||
sed -i Makefile -e 's/^\(LIBS=.*\)$/\1 -l:libssp.a/'
|
||||
set +x
|
||||
fi
|
||||
info "Calling make"
|
||||
@@ -484,6 +489,7 @@ if [ "$DOWIN" = "yes" ]; then
|
||||
|| error_cleanup "Could not configure"
|
||||
set +x
|
||||
else
|
||||
# Do not add -l:libssp:a statically because it is a shared build.
|
||||
set -x
|
||||
$configure --enable-debug --disable-flto --disable-gost $* $shared_cross_flag \
|
||||
|| error_cleanup "Could not configure"
|
||||
@@ -539,6 +545,12 @@ if [ "$DOWIN" = "yes" ]; then
|
||||
if test -f "$sspdll"; then
|
||||
cp "$sspdll" libunbound/.
|
||||
fi
|
||||
if test "$W64" = "no"; then
|
||||
# This could be solved with -static -static-libgcc -static-libstdc++.
|
||||
# The dependency on c++ is probably due to libexpat. But the copy
|
||||
# of the dll should work too. It may be needed for the libunbound.dll.
|
||||
cp /usr/i686-w64-mingw32/sys-root/mingw/bin/libgcc_s_dw2-1.dll libunbound/.
|
||||
fi
|
||||
# zipfile
|
||||
zip -r ../$file LICENSE README.txt unbound.exe unbound-anchor.exe unbound-host.exe unbound-control.exe unbound-checkconf.exe unbound-service-install.exe unbound-service-remove.exe unbound-control-setup.cmd example.conf service.conf root.key unbound-website.url create_unbound_ad_servers.cmd warmup.cmd unbound_cache.cmd Changelog libunbound
|
||||
info "Testing $file"
|
||||
@@ -596,6 +608,8 @@ rm -rf .git .travis.yml .gitattributes .github .gitignore || error_cleanup "Fail
|
||||
info "Adding libtool utils (libtoolize)."
|
||||
libtoolize -c --install || libtoolize -c || error_cleanup "Libtoolize failed."
|
||||
|
||||
# Turn this off, if the git repo times out for lookups.
|
||||
if test "updateconfigsub" = "false"; then
|
||||
# https://www.gnu.org/software/gettext/manual/html_node/config_002eguess.html
|
||||
info "Updating config.guess and config.sub"
|
||||
wget -O config.guess 'https://git.savannah.gnu.org/gitweb/?p=config.git;a=blob_plain;f=config.guess;hb=HEAD'
|
||||
@@ -609,12 +623,14 @@ if [ `uname -s | grep -i -c darwin` -ne 0 ]; then
|
||||
xattr -d com.apple.quarantine config.sub
|
||||
fi
|
||||
fi
|
||||
fi
|
||||
|
||||
info "Building configure script (autoreconf)."
|
||||
autoreconf -f || error_cleanup "Autoconf failed."
|
||||
|
||||
rm -r autom4te* || error_cleanup "Failed to remove autoconf cache directory."
|
||||
rm -f config.h.in~ || echo "ignore absence of config.h.in~ file."
|
||||
rm -f configure~ || echo "ignore absence of configure~ file."
|
||||
|
||||
info "Building lexer and parser."
|
||||
echo "#include \"config.h\"" > util/configlexer.c || error_cleanup "Failed to create configlexer"
|
||||
@@ -660,6 +676,7 @@ if [ "$RECONFIGURE" = "yes" ]; then
|
||||
autoreconf -f || error_cleanup "Autoconf failed."
|
||||
rm -r autom4te* || error_cleanup "Failed to remove autoconf cache directory."
|
||||
rm -f config.h.in~ || echo "ignore absence of config.h.in~ file."
|
||||
rm -f configure~ || echo "ignore absence of configure~ file."
|
||||
fi
|
||||
|
||||
replace_all doc/README
|
||||
@@ -691,7 +708,5 @@ cleanup
|
||||
storehash unbound-$version.tar.gz
|
||||
echo "create unbound-$version.tar.gz.asc with:"
|
||||
echo " gpg --armor --detach-sign --digest-algo SHA256 unbound-$version.tar.gz"
|
||||
echo " gpg --armor --detach-sign --digest-algo SHA256 unbound-$version.zip"
|
||||
echo " gpg --armor --detach-sign --digest-algo SHA256 unbound_setup_$version.exe"
|
||||
|
||||
info "Unbound distribution created successfully."
|
||||
|
||||
+17
-15
@@ -38,12 +38,14 @@ import os
|
||||
def dataHex(data, prefix=""):
|
||||
"""Converts binary string data to display representation form"""
|
||||
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])
|
||||
d = map(lambda x:x, data[i*16:i*16+17])
|
||||
count=0
|
||||
for ch in d:
|
||||
res += "%02X " % ch
|
||||
for i in range(0,17-len(d)):
|
||||
count+=1
|
||||
for i in range(0,17-count):
|
||||
res += " "
|
||||
res += "| "
|
||||
for ch in d:
|
||||
@@ -60,31 +62,31 @@ def logDnsMsg(qstate):
|
||||
r = qstate.return_msg.rep
|
||||
q = qstate.return_msg.qinfo
|
||||
|
||||
print "-"*100
|
||||
print("-"*100)
|
||||
print("Query: %s, type: %s (%d), class: %s (%d) " % (
|
||||
qstate.qinfo.qname_str, qstate.qinfo.qtype_str, qstate.qinfo.qtype,
|
||||
qstate.qinfo.qclass_str, qstate.qinfo.qclass))
|
||||
print "-"*100
|
||||
print "Return reply :: flags: %04X, QDcount: %d, Security:%d, TTL=%d" % (r.flags, r.qdcount, r.security, r.ttl)
|
||||
print " qinfo :: qname: %s %s, qtype: %s, qclass: %s" % (str(q.qname_list), q.qname_str, q.qtype_str, q.qclass_str)
|
||||
print("-"*100)
|
||||
print("Return reply :: flags: %04X, QDcount: %d, Security:%d, TTL=%d" % (r.flags, r.qdcount, r.security, r.ttl))
|
||||
print(" qinfo :: qname: %s %s, qtype: %s, qclass: %s" % (str(q.qname_list), q.qname_str, q.qtype_str, q.qclass_str))
|
||||
|
||||
if (r):
|
||||
print "Reply:"
|
||||
print("Reply:")
|
||||
for i in range(0, r.rrset_count):
|
||||
rr = r.rrsets[i]
|
||||
|
||||
rk = rr.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 = rr.entry.data
|
||||
for j in range(0,d.count+d.rrsig_count):
|
||||
print " ",j,":","TTL=",d.rr_ttl[j],
|
||||
if (j >= d.count): print "rrsig",
|
||||
print
|
||||
print dataHex(d.rr_data[j]," ")
|
||||
print(" ",j,":","TTL=",d.rr_ttl[j],)
|
||||
if (j >= d.count): print("rrsig",)
|
||||
print()
|
||||
print(dataHex(d.rr_data[j]," "))
|
||||
|
||||
print "-"*100
|
||||
print("-"*100)
|
||||
|
||||
def init(id, cfg):
|
||||
log_info("pythonmod: init called, module id is %d port: %d script: %s" % (id, cfg.port, mod_env['script']))
|
||||
|
||||
+18
-17
@@ -79,7 +79,7 @@
|
||||
i+(int)((unsigned int)name[i]) < len) {
|
||||
memmove(buf, name + i + 1, (unsigned int)name[i]);
|
||||
buf[(unsigned int)name[i]] = 0;
|
||||
PyList_SetItem(list, cnt, PyString_FromString(buf));
|
||||
PyList_SetItem(list, cnt, PyUnicode_FromString(buf));
|
||||
}
|
||||
i += ((unsigned int)name[i]) + 1;
|
||||
cnt++;
|
||||
@@ -96,7 +96,7 @@
|
||||
|
||||
list = PyList_New(len);
|
||||
for (i=0; i < len; i++) {
|
||||
PyList_SET_ITEM(list, i, PyString_FromString(array[i]));
|
||||
PyList_SET_ITEM(list, i, PyUnicode_FromString(array[i]));
|
||||
}
|
||||
return list;
|
||||
}
|
||||
@@ -207,7 +207,7 @@ struct query_info {
|
||||
char buf[LDNS_MAX_DOMAINLEN];
|
||||
buf[0] = '\0';
|
||||
dname_str((uint8_t*)PyBytes_AsString(dname), buf);
|
||||
return PyString_FromString(buf);
|
||||
return PyUnicode_FromString(buf);
|
||||
}
|
||||
%}
|
||||
|
||||
@@ -345,7 +345,7 @@ struct packed_rrset_data {
|
||||
PyObject* _get_data_rr_len(struct packed_rrset_data* d, int idx) {
|
||||
if ((d != NULL) && (idx >= 0) &&
|
||||
((size_t)idx < (d->count+d->rrsig_count)))
|
||||
return PyInt_FromLong(d->rr_len[idx]);
|
||||
return PyLong_FromLong(d->rr_len[idx]);
|
||||
return Py_None;
|
||||
}
|
||||
void _set_data_rr_ttl(struct packed_rrset_data* d, int idx, uint32_t ttl)
|
||||
@@ -357,7 +357,7 @@ struct packed_rrset_data {
|
||||
PyObject* _get_data_rr_ttl(struct packed_rrset_data* d, int idx) {
|
||||
if ((d != NULL) && (idx >= 0) &&
|
||||
((size_t)idx < (d->count+d->rrsig_count)))
|
||||
return PyInt_FromLong(d->rr_ttl[idx]);
|
||||
return PyLong_FromLong(d->rr_ttl[idx]);
|
||||
return Py_None;
|
||||
}
|
||||
PyObject* _get_data_rr_data(struct packed_rrset_data* d, int idx) {
|
||||
@@ -555,12 +555,12 @@ struct sockaddr_storage {};
|
||||
|
||||
if (ss->ss_family == AF_INET) {
|
||||
const struct sockaddr_in *sa4 = (struct sockaddr_in *)ss;
|
||||
return PyInt_FromLong(ntohs(sa4->sin_port));
|
||||
return PyLong_FromLong(ntohs(sa4->sin_port));
|
||||
}
|
||||
|
||||
if (ss->ss_family == AF_INET6) {
|
||||
const struct sockaddr_in6 *sa6 = (struct sockaddr_in6 *)ss;
|
||||
return PyInt_FromLong(ntohs(sa6->sin6_port));
|
||||
return PyLong_FromLong(ntohs(sa6->sin6_port));
|
||||
}
|
||||
|
||||
return Py_None;
|
||||
@@ -574,7 +574,7 @@ struct sockaddr_storage {};
|
||||
}
|
||||
|
||||
sa6 = (struct sockaddr_in6 *)ss;
|
||||
return PyInt_FromLong(ntohl(sa6->sin6_flowinfo));
|
||||
return PyLong_FromLong(ntohl(sa6->sin6_flowinfo));
|
||||
}
|
||||
|
||||
PyObject *_sockaddr_storage_scope_id(const struct sockaddr_storage *ss) {
|
||||
@@ -585,7 +585,7 @@ struct sockaddr_storage {};
|
||||
}
|
||||
|
||||
sa6 = (struct sockaddr_in6 *)ss;
|
||||
return PyInt_FromLong(ntohl(sa6->sin6_scope_id));
|
||||
return PyLong_FromLong(ntohl(sa6->sin6_scope_id));
|
||||
}
|
||||
%}
|
||||
|
||||
@@ -661,7 +661,7 @@ struct edns_option {
|
||||
%inline %{
|
||||
PyObject* _edns_option_opt_code_get(struct edns_option* option) {
|
||||
uint16_t opt_code = option->opt_code;
|
||||
return PyInt_FromLong(opt_code);
|
||||
return PyLong_FromLong(opt_code);
|
||||
}
|
||||
|
||||
PyObject* _edns_option_opt_data_get(struct edns_option* option) {
|
||||
@@ -729,11 +729,12 @@ struct module_env {
|
||||
int check_ratelimit,
|
||||
struct sockaddr_storage* addr, socklen_t addrlen,
|
||||
uint8_t* zone, size_t zonelen, int tcp_upstream, int ssl_upstream,
|
||||
char* tls_auth_name, struct module_qstate* q, int* was_ratelimited);
|
||||
char* tls_auth_name, struct module_qstate* q, int* was_ratelimited,
|
||||
int* ratelimit_incremented);
|
||||
void (*detach_subs)(struct module_qstate* qstate);
|
||||
int (*attach_sub)(struct module_qstate* qstate,
|
||||
struct query_info* qinfo, uint16_t qflags, int prime,
|
||||
int valrec, struct module_qstate** newq);
|
||||
struct query_info* qinfo, struct respip_client_info* cinfo,
|
||||
uint16_t qflags, int prime, int valrec, struct module_qstate** newq);
|
||||
void (*kill_sub)(struct module_qstate* newq);
|
||||
int (*detect_cycle)(struct module_qstate* qstate,
|
||||
struct query_info* qinfo, uint16_t flags, int prime,
|
||||
@@ -1626,7 +1627,7 @@ int edns_opt_list_append(struct edns_option** list, uint16_t code, size_t len,
|
||||
}
|
||||
result = PyObject_Call(func, py_args, py_kwargs);
|
||||
if (result) {
|
||||
res = PyInt_AsLong(result);
|
||||
res = PyLong_AsLong(result);
|
||||
}
|
||||
out:
|
||||
Py_XDECREF(py_edns);
|
||||
@@ -1710,7 +1711,7 @@ out:
|
||||
}
|
||||
result = PyObject_Call(func, py_args, py_kwargs);
|
||||
if (result) {
|
||||
res = PyInt_AsLong(result);
|
||||
res = PyLong_AsLong(result);
|
||||
}
|
||||
out:
|
||||
Py_XDECREF(py_qinfo);
|
||||
@@ -1764,7 +1765,7 @@ out:
|
||||
}
|
||||
result = PyObject_Call(func, py_args, py_kwargs);
|
||||
if (result) {
|
||||
res = PyInt_AsLong(result);
|
||||
res = PyLong_AsLong(result);
|
||||
}
|
||||
out:
|
||||
Py_XDECREF(py_qstate);
|
||||
@@ -1813,7 +1814,7 @@ out:
|
||||
}
|
||||
result = PyObject_Call(func, py_args, py_kwargs);
|
||||
if (result) {
|
||||
res = PyInt_AsLong(result);
|
||||
res = PyLong_AsLong(result);
|
||||
}
|
||||
out:
|
||||
Py_XDECREF(py_qstate);
|
||||
|
||||
+33
-37
@@ -246,14 +246,14 @@ log_py_err(void)
|
||||
}
|
||||
|
||||
/* And it should be a string all ready to go - duplicate it. */
|
||||
if (!PyString_Check(obResult) && !PyUnicode_Check(obResult)) {
|
||||
if (!PyBytes_Check(obResult) && !PyUnicode_Check(obResult)) {
|
||||
log_err("pythonmod: cannot print exception, "
|
||||
"StringIO.getvalue() result did not String_Check"
|
||||
" or Unicode_Check");
|
||||
goto cleanup;
|
||||
}
|
||||
if(PyString_Check(obResult)) {
|
||||
result = PyString_AsString(obResult);
|
||||
if(PyBytes_Check(obResult)) {
|
||||
result = PyBytes_AsString(obResult);
|
||||
} else {
|
||||
ascstr = PyUnicode_AsASCIIString(obResult);
|
||||
result = PyBytes_AsString(ascstr);
|
||||
@@ -450,11 +450,11 @@ int pythonmod_init(struct module_env* env, int id)
|
||||
|
||||
pe->data = PyDict_New();
|
||||
/* add the script filename to the global "mod_env" for trivial access */
|
||||
fname = PyString_FromString(pe->fname);
|
||||
fname = PyUnicode_FromString(pe->fname);
|
||||
if(PyDict_SetItemString(pe->data, "script", fname) < 0) {
|
||||
log_err("pythonmod: could not add item to dictionary");
|
||||
Py_XDECREF(fname);
|
||||
goto python_init_fail;
|
||||
goto fail_close_file;
|
||||
}
|
||||
Py_XDECREF(fname);
|
||||
Py_XINCREF(pe->data); /* reference will be stolen below */
|
||||
@@ -462,7 +462,7 @@ int pythonmod_init(struct module_env* env, int id)
|
||||
log_err("pythonmod: could not add mod_env object");
|
||||
Py_XDECREF(pe->data); /* 2 times, here and on python_init_fail; */
|
||||
/* on failure the reference is not stolen */
|
||||
goto python_init_fail;
|
||||
goto fail_close_file;
|
||||
}
|
||||
|
||||
if (PyRun_SimpleFile(script_py, pe->fname) < 0) {
|
||||
@@ -487,37 +487,34 @@ int pythonmod_init(struct module_env* env, int id)
|
||||
/* for python 3.9 and newer */
|
||||
char* fstr = NULL;
|
||||
size_t flen = 0;
|
||||
long pos = 0;
|
||||
log_err("pythonmod: can't parse Python script %s", pe->fname);
|
||||
/* print the error to logs too, run it again */
|
||||
fseek(script_py, 0, SEEK_END);
|
||||
flen = (size_t)ftell(script_py);
|
||||
pos = ftell(script_py);
|
||||
if (pos == -1L) {
|
||||
log_err("ftell failed to print parse error: %s: %s",
|
||||
pe->fname, strerror(errno));
|
||||
goto fail_close_file;
|
||||
}
|
||||
flen = (size_t)pos;
|
||||
#ifdef SIZE_MAX
|
||||
if(flen > SIZE_MAX-2) {
|
||||
log_err("script file too large");
|
||||
goto fail_close_file;
|
||||
}
|
||||
#endif
|
||||
fstr = malloc(flen+1);
|
||||
if(!fstr) {
|
||||
log_err("malloc failure to print parse error");
|
||||
|
||||
/* close the file */
|
||||
#if PY_MAJOR_VERSION < 3
|
||||
Py_XDECREF(PyFileObject);
|
||||
#else
|
||||
fclose(script_py);
|
||||
#endif
|
||||
|
||||
goto python_init_fail;
|
||||
log_err("malloc failure to print parse error");
|
||||
goto fail_close_file;
|
||||
}
|
||||
fseek(script_py, 0, SEEK_SET);
|
||||
if(fread(fstr, flen, 1, script_py) < 1) {
|
||||
log_err("file read failed to print parse error: %s: %s",
|
||||
log_err("file read failed to print parse error: %s: %s",
|
||||
pe->fname, strerror(errno));
|
||||
free(fstr);
|
||||
|
||||
/* close the file */
|
||||
#if PY_MAJOR_VERSION < 3
|
||||
Py_XDECREF(PyFileObject);
|
||||
#else
|
||||
fclose(script_py);
|
||||
#endif
|
||||
|
||||
goto python_init_fail;
|
||||
free(fstr);
|
||||
goto fail_close_file;
|
||||
}
|
||||
fstr[flen] = 0;
|
||||
/* we compile the string, but do not run it, to stop side-effects */
|
||||
@@ -527,21 +524,13 @@ int pythonmod_init(struct module_env* env, int id)
|
||||
#endif
|
||||
|
||||
log_py_err();
|
||||
|
||||
/* close the file */
|
||||
#if PY_MAJOR_VERSION < 3
|
||||
Py_XDECREF(PyFileObject);
|
||||
#else
|
||||
fclose(script_py);
|
||||
#endif
|
||||
|
||||
#if PY_MAJOR_VERSION <= 2 || (PY_MAJOR_VERSION == 3 && PY_MINOR_VERSION < 9)
|
||||
/* no cleanup needed for python before 3.9 */
|
||||
#else
|
||||
/* cleanup for python 3.9 and newer */
|
||||
free(fstr);
|
||||
#endif
|
||||
goto python_init_fail;
|
||||
goto fail_close_file;
|
||||
}
|
||||
|
||||
/* close the file */
|
||||
@@ -602,6 +591,13 @@ int pythonmod_init(struct module_env* env, int id)
|
||||
PyGILState_Release(gil);
|
||||
return 1;
|
||||
|
||||
fail_close_file:
|
||||
#if PY_MAJOR_VERSION < 3
|
||||
Py_XDECREF(PyFileObject);
|
||||
#else
|
||||
fclose(script_py);
|
||||
#endif
|
||||
|
||||
python_init_fail:
|
||||
Py_XDECREF(pe->module);
|
||||
Py_XDECREF(pe->dict);
|
||||
|
||||
+46
-24
@@ -899,27 +899,34 @@ respip_rewrite_reply(const struct query_info* qinfo,
|
||||
int rpz_cname_override = 0;
|
||||
char* log_name = NULL;
|
||||
|
||||
if(!cinfo)
|
||||
goto done;
|
||||
ctaglist = cinfo->taglist;
|
||||
ctaglen = cinfo->taglen;
|
||||
tag_actions = cinfo->tag_actions;
|
||||
tag_actions_size = cinfo->tag_actions_size;
|
||||
tag_datas = cinfo->tag_datas;
|
||||
tag_datas_size = cinfo->tag_datas_size;
|
||||
if(cinfo->view) {
|
||||
view = cinfo->view;
|
||||
lock_rw_rdlock(&view->lock);
|
||||
} else if(cinfo->view_name) {
|
||||
view = views_find_view(views, cinfo->view_name, 0);
|
||||
if(!view) {
|
||||
/* If the view no longer exists, the rewrite can not
|
||||
* be processed further. */
|
||||
verbose(VERB_ALGO, "respip: failed because view %s no "
|
||||
"longer exists", cinfo->view_name);
|
||||
return 0;
|
||||
if(!cinfo) {
|
||||
/* Internal mesh sub-query (e.g. dns64 A lookup): no
|
||||
* per-client view/tags, but global response-ip and RPZ
|
||||
* rpz-ip must still apply. */
|
||||
ctaglist = NULL; ctaglen = 0;
|
||||
tag_actions = NULL; tag_actions_size = 0;
|
||||
tag_datas = NULL; tag_datas_size = 0;
|
||||
} else {
|
||||
ctaglist = cinfo->taglist;
|
||||
ctaglen = cinfo->taglen;
|
||||
tag_actions = cinfo->tag_actions;
|
||||
tag_actions_size = cinfo->tag_actions_size;
|
||||
tag_datas = cinfo->tag_datas;
|
||||
tag_datas_size = cinfo->tag_datas_size;
|
||||
if(cinfo->view) {
|
||||
view = cinfo->view;
|
||||
lock_rw_rdlock(&view->lock);
|
||||
} else if(cinfo->view_name) {
|
||||
view = views_find_view(views, cinfo->view_name, 0);
|
||||
if(!view) {
|
||||
/* If the view no longer exists, the rewrite can not
|
||||
* be processed further. */
|
||||
verbose(VERB_ALGO, "respip: failed because view %s no "
|
||||
"longer exists", cinfo->view_name);
|
||||
return 0;
|
||||
}
|
||||
/* The view is rdlocked by views_find_view. */
|
||||
}
|
||||
/* The view is rdlocked by views_find_view. */
|
||||
}
|
||||
|
||||
log_assert(ipset);
|
||||
@@ -973,6 +980,9 @@ respip_rewrite_reply(const struct query_info* qinfo,
|
||||
lock_rw_unlock(&raddr->lock);
|
||||
lock_rw_unlock(&a->lock);
|
||||
lock_rw_unlock(&az->rpz_lock);
|
||||
if(view) {
|
||||
lock_rw_unlock(&view->lock);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
if(rpz_used) {
|
||||
@@ -1074,7 +1084,8 @@ generate_cname_request(struct module_qstate* qstate,
|
||||
subqi.qtype = qstate->qinfo.qtype;
|
||||
subqi.qclass = qstate->qinfo.qclass;
|
||||
fptr_ok(fptr_whitelist_modenv_attach_sub(qstate->env->attach_sub));
|
||||
return (*qstate->env->attach_sub)(qstate, &subqi, BIT_RD, 0, 0, &subq);
|
||||
return (*qstate->env->attach_sub)(qstate, &subqi,
|
||||
qstate->client_info, BIT_RD, 0, 0, &subq);
|
||||
}
|
||||
|
||||
void
|
||||
@@ -1110,7 +1121,13 @@ respip_operate(struct module_qstate* qstate, enum module_ev event, int id,
|
||||
if((qstate->qinfo.qtype == LDNS_RR_TYPE_A ||
|
||||
qstate->qinfo.qtype == LDNS_RR_TYPE_AAAA ||
|
||||
qstate->qinfo.qtype == LDNS_RR_TYPE_ANY) &&
|
||||
qstate->return_msg && qstate->return_msg->rep) {
|
||||
qstate->return_msg && qstate->return_msg->rep &&
|
||||
!(qstate->env->need_to_validate &&
|
||||
(!(qstate->query_flags & BIT_CD)
|
||||
|| qstate->env->cfg->ignore_cd) &&
|
||||
(qstate->return_msg->rep->security <= sec_status_bogus
|
||||
|| qstate->return_msg->rep->security ==
|
||||
sec_status_secure_sentinel_fail))) {
|
||||
struct reply_info* new_rep = qstate->return_msg->rep;
|
||||
struct ub_packed_rrset_key* alias_rrset = NULL;
|
||||
struct respip_action_info actinfo = {0, 0, 0, 0, NULL, 0, NULL};
|
||||
@@ -1147,8 +1164,10 @@ respip_operate(struct module_qstate* qstate, enum module_ev event, int id,
|
||||
* clients. */
|
||||
qstate->is_drop = 1;
|
||||
} else if(alias_rrset) {
|
||||
if(!generate_cname_request(qstate, alias_rrset))
|
||||
if(!generate_cname_request(qstate, alias_rrset)) {
|
||||
errinf(qstate, "Could not generate CNAME request");
|
||||
goto servfail;
|
||||
}
|
||||
next_state = module_wait_subquery;
|
||||
}
|
||||
qstate->return_msg->rep = new_rep;
|
||||
@@ -1162,6 +1181,7 @@ respip_operate(struct module_qstate* qstate, enum module_ev event, int id,
|
||||
servfail:
|
||||
qstate->return_rcode = LDNS_RCODE_SERVFAIL;
|
||||
qstate->return_msg = NULL;
|
||||
qstate->ext_state[id] = module_finished;
|
||||
}
|
||||
|
||||
int
|
||||
@@ -1233,7 +1253,8 @@ respip_inform_super(struct module_qstate* qstate, int id,
|
||||
struct respip_qstate* rq = (struct respip_qstate*)super->minfo[id];
|
||||
struct reply_info* new_rep = NULL;
|
||||
|
||||
rq->state = RESPIP_SUBQUERY_FINISHED;
|
||||
if(rq)
|
||||
rq->state = RESPIP_SUBQUERY_FINISHED;
|
||||
|
||||
/* respip subquery should have always been created with a valid reply
|
||||
* in super. */
|
||||
@@ -1257,6 +1278,7 @@ respip_inform_super(struct module_qstate* qstate, int id,
|
||||
return;
|
||||
|
||||
fail:
|
||||
errinf(super, "CNAME lookup failed");
|
||||
super->return_rcode = LDNS_RCODE_SERVFAIL;
|
||||
super->return_msg = NULL;
|
||||
return;
|
||||
|
||||
+1
-1
@@ -276,7 +276,7 @@ void respip_inform_print(struct respip_action_info* respip_actinfo,
|
||||
* @param addrlen: length of addr.
|
||||
* @param net: netblock to lookup.
|
||||
* @param create: create node if it does not exist when 1.
|
||||
* @param ipstr: human redable ip string, for logging.
|
||||
* @param ipstr: human readable ip string, for logging.
|
||||
* @return newly created of found node, not holding lock.
|
||||
*/
|
||||
struct resp_addr*
|
||||
|
||||
+474
-141
File diff suppressed because it is too large
Load Diff
+44
-2
@@ -118,6 +118,8 @@ struct auth_zone {
|
||||
char* zonefile;
|
||||
/** fallback to the internet on failure or ttl-expiry of auth zone */
|
||||
int fallback_enabled;
|
||||
/** the time when zone was transferred from upstream */
|
||||
time_t soa_zone_acquired;
|
||||
/** the zone has expired (enabled by the xfer worker), fallback
|
||||
* happens if that option is enabled. */
|
||||
int zone_expired;
|
||||
@@ -142,6 +144,8 @@ struct auth_zone {
|
||||
struct module_env* zonemd_callback_env;
|
||||
/** for the zonemd callback, the type of data looked up */
|
||||
uint16_t zonemd_callback_qtype;
|
||||
/** for the zonemd callback, the unique info */
|
||||
void* zonemd_callback_unique_info;
|
||||
/** zone has been deleted */
|
||||
int zone_deleted;
|
||||
/** deletelist pointer, unused normally except during delete */
|
||||
@@ -151,6 +155,10 @@ struct auth_zone {
|
||||
struct auth_zone* rpz_az_next;
|
||||
/** previous auth zone containing RPZ data, or NULL */
|
||||
struct auth_zone* rpz_az_prev;
|
||||
/** The maximum auth zone transfer size, in bytes. */
|
||||
size_t max_transfer_size;
|
||||
/** The maximum auth zone transfer time taken, in msec. */
|
||||
int max_transfer_time;
|
||||
};
|
||||
|
||||
/**
|
||||
@@ -261,6 +269,8 @@ struct auth_xfer {
|
||||
int zone_expired;
|
||||
/** do we have a zone (if 0, no zone data at all) */
|
||||
int have_zone;
|
||||
/** the time when zone was transferred from upstream */
|
||||
time_t soa_zone_acquired;
|
||||
|
||||
/** current serial (from SOA), if we have no zone, 0 */
|
||||
uint32_t serial;
|
||||
@@ -279,6 +289,15 @@ struct auth_xfer {
|
||||
* this is renewed every SOA probe and transfer. On zone load
|
||||
* from zonefile it is also set (with probe set soon to check) */
|
||||
time_t lease_time;
|
||||
|
||||
/** The maximum auth zone transfer size, in bytes. */
|
||||
size_t max_transfer_size;
|
||||
/** The maximum auth zone transfer time taken, in msec. */
|
||||
int max_transfer_time;
|
||||
/** the zone is an rpz zone */
|
||||
int is_rpz;
|
||||
/** the number of IXFRs since the last full transfer. */
|
||||
int num_ixfrs;
|
||||
};
|
||||
|
||||
/**
|
||||
@@ -327,6 +346,8 @@ struct auth_probe {
|
||||
|
||||
/** for the hostname lookups, which master is current */
|
||||
struct auth_master* lookup_target;
|
||||
/** for the lookup, the callback unique info */
|
||||
void* lookup_unique_info;
|
||||
/** are we looking up A or AAAA, first A, then AAAA (if ip6 enabled) */
|
||||
int lookup_aaaa;
|
||||
/** we only want to do lookups for making config work (for notify),
|
||||
@@ -375,12 +396,18 @@ struct auth_transfer {
|
||||
struct auth_chunk* chunks_first;
|
||||
/** last element in chunks list (to append new data at the end) */
|
||||
struct auth_chunk* chunks_last;
|
||||
/** running total of bytes held in chunks_first..chunks_last */
|
||||
size_t chunks_total;
|
||||
/** start time of the transfer */
|
||||
struct timeval start_time;
|
||||
|
||||
/** list of upstream masters for this zone, from config */
|
||||
struct auth_master* masters;
|
||||
|
||||
/** for the hostname lookups, which master is current */
|
||||
struct auth_master* lookup_target;
|
||||
/** for the lookup, the callback unique info */
|
||||
void* lookup_unique_info;
|
||||
/** are we looking up A or AAAA, first A, then AAAA (if ip6 enabled) */
|
||||
int lookup_aaaa;
|
||||
|
||||
@@ -550,9 +577,10 @@ int auth_zones_lookup(struct auth_zones* az, struct query_info* qinfo,
|
||||
* @param temp: temporary storage region.
|
||||
* @return false if not answered
|
||||
*/
|
||||
int auth_zones_answer(struct auth_zones* az, struct module_env* env,
|
||||
int auth_zones_downstream_answer(struct auth_zones* az, struct module_env* env,
|
||||
struct query_info* qinfo, struct edns_data* edns,
|
||||
struct comm_reply* repinfo, struct sldns_buffer* buf, struct regional* temp);
|
||||
struct comm_reply* repinfo, struct sldns_buffer* buf,
|
||||
struct regional* temp);
|
||||
|
||||
/**
|
||||
* Find the auth zone that is above the given qname.
|
||||
@@ -799,6 +827,14 @@ size_t auth_zones_get_mem(struct auth_zones* zones);
|
||||
void auth_xfer_pickup_initial_zone(struct auth_xfer* x,
|
||||
struct module_env* env);
|
||||
|
||||
/**
|
||||
* Initial pick up of the auth zone, it sets the acquired time.
|
||||
* @param z: the zone, write locked by caller.
|
||||
* @param env: environment of the worker, with current time.
|
||||
*/
|
||||
void auth_zone_pickup_initial_zone(struct auth_zone* z,
|
||||
struct module_env* env);
|
||||
|
||||
/**
|
||||
* Delete auth xfer structure
|
||||
* @param xfr: delete this xfer and its tasks.
|
||||
@@ -815,4 +851,10 @@ void auth_xfer_delete(struct auth_xfer* xfr);
|
||||
*/
|
||||
void xfr_disown_tasks(struct auth_xfer* xfr, struct worker* worker);
|
||||
|
||||
/** count number of open and closed parenthesis in a chunkline */
|
||||
int chunkline_count_parens(struct sldns_buffer* buf, size_t start);
|
||||
|
||||
/** Clear data in auth zone */
|
||||
void auth_zone_clear_data(struct auth_zone* z);
|
||||
|
||||
#endif /* SERVICES_AUTHZONE_H */
|
||||
|
||||
Vendored
+101
-35
@@ -43,6 +43,7 @@
|
||||
#include "iterator/iter_utils.h"
|
||||
#include "validator/val_nsec.h"
|
||||
#include "validator/val_utils.h"
|
||||
#include "iterator/iter_utils.h"
|
||||
#include "services/cache/dns.h"
|
||||
#include "services/cache/rrset.h"
|
||||
#include "util/data/msgparse.h"
|
||||
@@ -60,10 +61,10 @@
|
||||
* @param rep: contains list of rrsets to store.
|
||||
* @param now: current time.
|
||||
* @param leeway: during prefetch how much leeway to update TTLs.
|
||||
* This makes rrsets (other than type NS) timeout sooner so they get
|
||||
* updated with a new full TTL.
|
||||
* Type NS does not get this, because it must not be refreshed from the
|
||||
* child domain, but keep counting down properly.
|
||||
* This makes rrsets expire sooner so they get updated with a new full
|
||||
* TTL.
|
||||
* Child side type NS does get this but TTL checks are done using the time
|
||||
* the query was created rather than the time the answer was received.
|
||||
* @param pside: if from parentside discovered NS, so that its NS is okay
|
||||
* in a prefetch situation to be updated (without becoming sticky).
|
||||
* @param qrep: update rrsets here if cache is better
|
||||
@@ -100,11 +101,20 @@ store_rrsets(struct module_env* env, struct reply_info* rep, time_t now,
|
||||
rep->ref[i].id != rep->ref[i].key->id)
|
||||
ck = NULL;
|
||||
else ck = packed_rrset_copy_region(
|
||||
rep->ref[i].key, region, now);
|
||||
rep->ref[i].key, region,
|
||||
((ntohs(rep->ref[i].key->rk.type)==
|
||||
LDNS_RR_TYPE_NS && !pside)?qstarttime:now));
|
||||
lock_rw_unlock(&rep->ref[i].key->entry.lock);
|
||||
if(ck) {
|
||||
/* use cached copy if memory allows */
|
||||
qrep->rrsets[i] = ck;
|
||||
ttl = ((struct packed_rrset_data*)
|
||||
ck->entry.data)->ttl;
|
||||
if(ttl < qrep->ttl) {
|
||||
qrep->ttl = ttl;
|
||||
qrep->prefetch_ttl = PREFETCH_TTL_CALC(qrep->ttl);
|
||||
qrep->serve_expired_ttl = qrep->ttl + SERVE_EXPIRED_TTL;
|
||||
}
|
||||
}
|
||||
}
|
||||
/* no break: also copy key item */
|
||||
@@ -169,10 +179,12 @@ dns_cache_store_msg(struct module_env* env, struct query_info* qinfo,
|
||||
|
||||
/* there was a reply_info_sortref(rep) here but it seems to be
|
||||
* unnecessary, because the cache gets locked per rrset. */
|
||||
reply_info_set_ttls(rep, *env->now);
|
||||
if((flags & DNSCACHE_STORE_EXPIRED_MSG_CACHEDB)) {
|
||||
reply_info_absolute_ttls(rep, *env->now, *env->now - ttl);
|
||||
} else reply_info_set_ttls(rep, *env->now);
|
||||
store_rrsets(env, rep, *env->now, leeway, pside, qrep, region,
|
||||
qstarttime);
|
||||
if(ttl == 0 && !(flags & DNSCACHE_STORE_ZEROTTL)) {
|
||||
if(ttl == 0) {
|
||||
/* we do not store the message, but we did store the RRs,
|
||||
* which could be useful for delegation information */
|
||||
verbose(VERB_ALGO, "TTL 0: dropped msg from cache");
|
||||
@@ -221,8 +233,15 @@ find_closest_of_type(struct module_env* env, uint8_t* qname, size_t qnamelen,
|
||||
|
||||
/* snip off front part of qname until the type is found */
|
||||
while(qnamelen > 0) {
|
||||
if((rrset = rrset_cache_lookup(env->rrset_cache, qname,
|
||||
qnamelen, searchtype, qclass, 0, now, 0))) {
|
||||
rrset = rrset_cache_lookup(env->rrset_cache, qname,
|
||||
qnamelen, searchtype, qclass, 0, now, 0);
|
||||
if(!rrset && searchtype == LDNS_RR_TYPE_DNAME)
|
||||
/* If not found, for type DNAME, try 0TTL stored,
|
||||
* for its grace period. */
|
||||
rrset = rrset_cache_lookup(env->rrset_cache, qname,
|
||||
qnamelen, searchtype, qclass,
|
||||
PACKED_RRSET_UPSTREAM_0TTL, now, 0);
|
||||
if(rrset) {
|
||||
uint8_t* origqname = qname;
|
||||
size_t origqnamelen = qnamelen;
|
||||
if(!noexpiredabove)
|
||||
@@ -259,6 +278,8 @@ find_closest_of_type(struct module_env* env, uint8_t* qname, size_t qnamelen,
|
||||
|
||||
/* snip off front label */
|
||||
lablen = *qname;
|
||||
if(lablen == 0)
|
||||
break;
|
||||
qname += lablen + 1;
|
||||
qnamelen -= lablen + 1;
|
||||
}
|
||||
@@ -272,8 +293,10 @@ addr_to_additional(struct ub_packed_rrset_key* rrset, struct regional* region,
|
||||
{
|
||||
if((msg->rep->rrsets[msg->rep->rrset_count] =
|
||||
packed_rrset_copy_region(rrset, region, now))) {
|
||||
struct packed_rrset_data* d = rrset->entry.data;
|
||||
msg->rep->ar_numrrsets++;
|
||||
msg->rep->rrset_count++;
|
||||
UPDATE_TTL_FROM_RRSET(msg->rep->ttl, d->ttl);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -456,8 +479,10 @@ find_add_ds(struct module_env* env, struct regional* region,
|
||||
/* add it to auth section. This is the second rrset. */
|
||||
if((msg->rep->rrsets[msg->rep->rrset_count] =
|
||||
packed_rrset_copy_region(rrset, region, now))) {
|
||||
struct packed_rrset_data* d = rrset->entry.data;
|
||||
msg->rep->ns_numrrsets++;
|
||||
msg->rep->rrset_count++;
|
||||
UPDATE_TTL_FROM_RRSET(msg->rep->ttl, d->ttl);
|
||||
}
|
||||
lock_rw_unlock(&rrset->entry.lock);
|
||||
}
|
||||
@@ -487,6 +512,8 @@ dns_msg_create(uint8_t* qname, size_t qnamelen, uint16_t qtype,
|
||||
return NULL; /* integer overflow protection */
|
||||
msg->rep->flags = BIT_QR; /* with QR, no AA */
|
||||
msg->rep->qdcount = 1;
|
||||
msg->rep->ttl = MAX_TTL; /* will be updated (brought down) while we add
|
||||
* rrsets to the message */
|
||||
msg->rep->reason_bogus = LDNS_EDE_NONE;
|
||||
msg->rep->rrsets = (struct ub_packed_rrset_key**)
|
||||
regional_alloc(region,
|
||||
@@ -497,24 +524,28 @@ dns_msg_create(uint8_t* qname, size_t qnamelen, uint16_t qtype,
|
||||
}
|
||||
|
||||
int
|
||||
dns_msg_authadd(struct dns_msg* msg, struct regional* region,
|
||||
dns_msg_authadd(struct dns_msg* msg, struct regional* region,
|
||||
struct ub_packed_rrset_key* rrset, time_t now)
|
||||
{
|
||||
if(!(msg->rep->rrsets[msg->rep->rrset_count++] =
|
||||
struct packed_rrset_data* d = rrset->entry.data;
|
||||
if(!(msg->rep->rrsets[msg->rep->rrset_count++] =
|
||||
packed_rrset_copy_region(rrset, region, now)))
|
||||
return 0;
|
||||
msg->rep->ns_numrrsets++;
|
||||
UPDATE_TTL_FROM_RRSET(msg->rep->ttl, d->ttl);
|
||||
return 1;
|
||||
}
|
||||
|
||||
int
|
||||
dns_msg_ansadd(struct dns_msg* msg, struct regional* region,
|
||||
dns_msg_ansadd(struct dns_msg* msg, struct regional* region,
|
||||
struct ub_packed_rrset_key* rrset, time_t now)
|
||||
{
|
||||
if(!(msg->rep->rrsets[msg->rep->rrset_count++] =
|
||||
struct packed_rrset_data* d = rrset->entry.data;
|
||||
if(!(msg->rep->rrsets[msg->rep->rrset_count++] =
|
||||
packed_rrset_copy_region(rrset, region, now)))
|
||||
return 0;
|
||||
msg->rep->an_numrrsets++;
|
||||
UPDATE_TTL_FROM_RRSET(msg->rep->ttl, d->ttl);
|
||||
return 1;
|
||||
}
|
||||
|
||||
@@ -556,8 +587,12 @@ dns_cache_find_delegation(struct module_env* env, uint8_t* qname,
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
if(!delegpt_rrset_add_ns(dp, region, nskey, 0))
|
||||
if(!delegpt_rrset_add_ns(dp, region, nskey, 0,
|
||||
deleg_port_number(env))) {
|
||||
lock_rw_unlock(&nskey->entry.lock);
|
||||
log_err("find_delegation: addns out of memory");
|
||||
return NULL;
|
||||
}
|
||||
lock_rw_unlock(&nskey->entry.lock); /* first unlock before next lookup*/
|
||||
/* find and add DS/NSEC (if any) */
|
||||
if(msg)
|
||||
@@ -585,6 +620,7 @@ gen_dns_msg(struct regional* region, struct query_info* q, size_t num)
|
||||
sizeof(struct reply_info) - sizeof(struct rrset_ref));
|
||||
if(!msg->rep)
|
||||
return NULL;
|
||||
msg->rep->ttl = MAX_TTL;
|
||||
msg->rep->reason_bogus = LDNS_EDE_NONE;
|
||||
msg->rep->reason_bogus_str = NULL;
|
||||
if(num > RR_COUNT_MAX)
|
||||
@@ -606,13 +642,13 @@ tomsg(struct module_env* env, struct query_info* q, struct reply_info* r,
|
||||
size_t i;
|
||||
int is_expired = 0;
|
||||
time_t now_control = now;
|
||||
if(now > r->ttl) {
|
||||
if(TTL_IS_EXPIRED(r->ttl, now)) {
|
||||
/* Check if we are allowed to serve expired */
|
||||
if(!allow_expired || !reply_info_can_answer_expired(r, now))
|
||||
return NULL;
|
||||
/* Change the current time so we can pass the below TTL checks when
|
||||
* serving expired data. */
|
||||
now_control = r->ttl - env->cfg->serve_expired_reply_ttl;
|
||||
/* Change the current time so we can pass the below TTL checks
|
||||
* when serving expired data. */
|
||||
now_control = 0;
|
||||
is_expired = 1;
|
||||
}
|
||||
|
||||
@@ -620,15 +656,6 @@ tomsg(struct module_env* env, struct query_info* q, struct reply_info* r,
|
||||
if(!msg) return NULL;
|
||||
msg->rep->flags = r->flags;
|
||||
msg->rep->qdcount = r->qdcount;
|
||||
msg->rep->ttl = is_expired
|
||||
?SERVE_EXPIRED_REPLY_TTL
|
||||
:r->ttl - now;
|
||||
if(r->prefetch_ttl > now)
|
||||
msg->rep->prefetch_ttl = r->prefetch_ttl - now;
|
||||
else
|
||||
msg->rep->prefetch_ttl = PREFETCH_TTL_CALC(msg->rep->ttl);
|
||||
msg->rep->serve_expired_ttl = msg->rep->ttl + SERVE_EXPIRED_TTL;
|
||||
msg->rep->serve_expired_norec_ttl = 0;
|
||||
msg->rep->security = r->security;
|
||||
msg->rep->an_numrrsets = r->an_numrrsets;
|
||||
msg->rep->ns_numrrsets = r->ns_numrrsets;
|
||||
@@ -656,13 +683,30 @@ tomsg(struct module_env* env, struct query_info* q, struct reply_info* r,
|
||||
return NULL;
|
||||
}
|
||||
for(i=0; i<msg->rep->rrset_count; i++) {
|
||||
struct packed_rrset_data* d;
|
||||
msg->rep->rrsets[i] = packed_rrset_copy_region(r->rrsets[i],
|
||||
region, now);
|
||||
if(!msg->rep->rrsets[i]) {
|
||||
rrset_array_unlock(r->ref, r->rrset_count);
|
||||
return NULL;
|
||||
}
|
||||
d = msg->rep->rrsets[i]->entry.data;
|
||||
UPDATE_TTL_FROM_RRSET(msg->rep->ttl, d->ttl);
|
||||
}
|
||||
if(msg->rep->rrset_count < 1) {
|
||||
msg->rep->ttl = is_expired
|
||||
?SERVE_EXPIRED_REPLY_TTL
|
||||
:r->ttl - now;
|
||||
if(r->prefetch_ttl > now)
|
||||
msg->rep->prefetch_ttl = r->prefetch_ttl - now;
|
||||
else
|
||||
msg->rep->prefetch_ttl = PREFETCH_TTL_CALC(msg->rep->ttl);
|
||||
} else {
|
||||
/* msg->rep->ttl has been updated through the RRSets above */
|
||||
msg->rep->prefetch_ttl = PREFETCH_TTL_CALC(msg->rep->ttl);
|
||||
}
|
||||
msg->rep->serve_expired_ttl = msg->rep->ttl + SERVE_EXPIRED_TTL;
|
||||
msg->rep->serve_expired_norec_ttl = 0;
|
||||
if(env)
|
||||
rrset_array_unlock_touch(env->rrset_cache, scratch, r->ref,
|
||||
r->rrset_count);
|
||||
@@ -675,10 +719,16 @@ struct dns_msg*
|
||||
dns_msg_deepcopy_region(struct dns_msg* origin, struct regional* region)
|
||||
{
|
||||
size_t i;
|
||||
struct ub_packed_rrset_key** saved_rrsets;
|
||||
struct dns_msg* res = NULL;
|
||||
size_t rep_alloc_size = sizeof(struct reply_info)
|
||||
- sizeof(struct rrset_ref); /* this is the size of res->rep
|
||||
allocated in gen_dns_msg() */
|
||||
res = gen_dns_msg(region, &origin->qinfo, origin->rep->rrset_count);
|
||||
if(!res) return NULL;
|
||||
*res->rep = *origin->rep;
|
||||
saved_rrsets = res->rep->rrsets; /* save rrsets alloc by gen_dns_msg */
|
||||
memcpy(res->rep, origin->rep, rep_alloc_size);
|
||||
res->rep->rrsets = saved_rrsets;
|
||||
if(origin->rep->reason_bogus_str) {
|
||||
res->rep->reason_bogus_str = regional_strdup(region,
|
||||
origin->rep->reason_bogus_str);
|
||||
@@ -701,7 +751,7 @@ rrset_msg(struct ub_packed_rrset_key* rrset, struct regional* region,
|
||||
struct dns_msg* msg;
|
||||
struct packed_rrset_data* d = (struct packed_rrset_data*)
|
||||
rrset->entry.data;
|
||||
if(now > d->ttl)
|
||||
if(TTL_IS_EXPIRED(d->ttl, now))
|
||||
return NULL;
|
||||
msg = gen_dns_msg(region, q, 1); /* only the CNAME (or other) RRset */
|
||||
if(!msg)
|
||||
@@ -736,8 +786,20 @@ synth_dname_msg(struct ub_packed_rrset_key* rrset, struct regional* region,
|
||||
rrset->entry.data;
|
||||
uint8_t* newname, *dtarg = NULL;
|
||||
size_t newlen, dtarglen;
|
||||
if(now > d->ttl)
|
||||
return NULL;
|
||||
time_t rr_ttl;
|
||||
int graceperiod = 0;
|
||||
if(TTL_IS_EXPIRED(d->ttl, now)) {
|
||||
/* Allow TTL=0 DNAME from upstream within grace period */
|
||||
if(!(rrset->rk.flags & PACKED_RRSET_UPSTREAM_0TTL))
|
||||
return NULL;
|
||||
rr_ttl = 0;
|
||||
/* Since PACKED_RRSET_UPSTREAM_0TTL set the flag that
|
||||
* the grace period has been applied, this stops the rrset
|
||||
* from getting stored back into the cache with a bigger TTL.*/
|
||||
graceperiod = 1;
|
||||
} else {
|
||||
rr_ttl = d->ttl - now;
|
||||
}
|
||||
/* only allow validated (with DNSSEC) DNAMEs used from cache
|
||||
* for insecure DNAMEs, query again. */
|
||||
*sec_status = d->security;
|
||||
@@ -749,7 +811,7 @@ synth_dname_msg(struct ub_packed_rrset_key* rrset, struct regional* region,
|
||||
msg->rep->flags = BIT_QR; /* reply, no AA, no error */
|
||||
msg->rep->authoritative = 0; /* reply stored in cache can't be authoritative */
|
||||
msg->rep->qdcount = 1;
|
||||
msg->rep->ttl = d->ttl - now;
|
||||
msg->rep->ttl = rr_ttl;
|
||||
msg->rep->prefetch_ttl = PREFETCH_TTL_CALC(msg->rep->ttl);
|
||||
msg->rep->serve_expired_ttl = msg->rep->ttl + SERVE_EXPIRED_TTL;
|
||||
msg->rep->serve_expired_norec_ttl = 0;
|
||||
@@ -762,6 +824,8 @@ synth_dname_msg(struct ub_packed_rrset_key* rrset, struct regional* region,
|
||||
msg->rep->rrsets[0] = packed_rrset_copy_region(rrset, region, now);
|
||||
if(!msg->rep->rrsets[0]) /* copy DNAME */
|
||||
return NULL;
|
||||
if(graceperiod)
|
||||
msg->rep->rrsets[0]->rk.flags |= PACKED_RRSET_0TTL_GRACE;
|
||||
/* synth CNAME rrset */
|
||||
get_cname_target(rrset, &dtarg, &dtarglen);
|
||||
if(!dtarg)
|
||||
@@ -801,7 +865,7 @@ synth_dname_msg(struct ub_packed_rrset_key* rrset, struct regional* region,
|
||||
if(!newd)
|
||||
return NULL;
|
||||
ck->entry.data = newd;
|
||||
newd->ttl = d->ttl - now; /* RFC6672: synth CNAME TTL == DNAME TTL */
|
||||
newd->ttl = rr_ttl; /* RFC6672: synth CNAME TTL == DNAME TTL */
|
||||
newd->count = 1;
|
||||
newd->rrsig_count = 0;
|
||||
newd->trust = rrset_trust_ans_noAA;
|
||||
@@ -844,6 +908,8 @@ fill_any(struct module_env* env,
|
||||
/* set NOTIMPL for RFC 8482 */
|
||||
msg->rep->flags |= LDNS_RCODE_NOTIMPL;
|
||||
msg->rep->security = sec_status_indeterminate;
|
||||
msg->rep->ttl = 1; /* empty NOTIMPL response will never be
|
||||
* updated with rrsets, set TTL to 1 */
|
||||
return msg;
|
||||
}
|
||||
|
||||
@@ -1013,7 +1079,7 @@ dns_cache_lookup(struct module_env* env,
|
||||
if(env->cfg->harden_below_nxdomain) {
|
||||
while(!dname_is_root(k.qname)) {
|
||||
if(dpname && dpnamelen
|
||||
&& !dname_subdomain_c(k.qname, dpname))
|
||||
&& !dname_strict_subdomain_c(k.qname, dpname))
|
||||
break; /* no synth nxdomain above the stub */
|
||||
dname_remove_label(&k.qname, &k.qname_len);
|
||||
h = query_info_hash(&k, flags);
|
||||
@@ -1069,7 +1135,7 @@ dns_cache_store(struct module_env* env, struct query_info* msgqinf,
|
||||
msgqinf->qclass, flags, 0, 1);
|
||||
if(e) {
|
||||
struct reply_info* cached = e->entry.data;
|
||||
if(cached->ttl < *env->now
|
||||
if(TTL_IS_EXPIRED(cached->ttl, *env->now)
|
||||
&& reply_info_could_use_expired(cached, *env->now)
|
||||
/* If we are validating make sure only
|
||||
* validating modules can update such messages.
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user